{"version":3,"file":"ol.js","sources":["../src/ol/util.js","../src/ol/AssertionError.js","../src/ol/CollectionEventType.js","../src/ol/ObjectEventType.js","../src/ol/obj.js","../src/ol/events.js","../src/ol/functions.js","../src/ol/Disposable.js","../src/ol/events/Event.js","../src/ol/events/EventTarget.js","../src/ol/events/EventType.js","../src/ol/Observable.js","../src/ol/Object.js","../src/ol/Collection.js","../src/ol/asserts.js","../src/ol/extent/Corner.js","../src/ol/extent/Relationship.js","../src/ol/extent.js","../src/ol/geom/flat/transform.js","../src/ol/math.js","../src/ol/geom/GeometryType.js","../src/ol/sphere.js","../src/ol/proj/Units.js","../src/ol/proj/Projection.js","../src/ol/proj/epsg3857.js","../src/ol/proj/epsg4326.js","../src/ol/proj/projections.js","../src/ol/proj/transforms.js","../src/ol/proj.js","../src/ol/transform.js","../src/ol/geom/Geometry.js","../src/ol/color.js","../src/ol/colorlike.js","../src/ol/dom.js","../src/ol/webgl.js","../src/ol/has.js","../src/ol/css.js","../src/ol/ImageState.js","../src/ol/structs/LRUCache.js","../src/ol/render/canvas.js","../src/ol/style/Image.js","../src/ol/style/RegularShape.js","../src/ol/style/Circle.js","../src/ol/style/Fill.js","../src/ol/style/Stroke.js","../src/ol/style/Style.js","../src/ol/Feature.js","../src/ol/GeolocationProperty.js","../src/ol/array.js","../src/ol/geom/GeometryLayout.js","../src/ol/geom/SimpleGeometry.js","../src/ol/geom/flat/area.js","../src/ol/geom/flat/closest.js","../src/ol/geom/flat/deflate.js","../src/ol/geom/flat/inflate.js","../src/ol/geom/flat/simplify.js","../src/ol/geom/LinearRing.js","../src/ol/geom/Point.js","../src/ol/geom/flat/contains.js","../src/ol/geom/flat/interiorpoint.js","../src/ol/geom/flat/segments.js","../src/ol/geom/flat/intersectsextent.js","../src/ol/geom/flat/reverse.js","../src/ol/geom/flat/orient.js","../src/ol/geom/Polygon.js","../src/ol/Geolocation.js","../src/ol/string.js","../src/ol/coordinate.js","../src/ol/geom/flat/interpolate.js","../src/ol/geom/flat/length.js","../src/ol/geom/LineString.js","../src/ol/geom/flat/geodesic.js","../src/ol/render/EventType.js","../src/ol/style/TextPlacement.js","../src/ol/style/Text.js","../src/ol/Graticule.js","../src/ol/ImageBase.js","../src/ol/Image.js","../src/ol/TileState.js","../src/ol/easing.js","../src/ol/Tile.js","../src/ol/ImageTile.js","../src/ol/Kinetic.js","../src/ol/MapEvent.js","../src/ol/MapBrowserEvent.js","../src/ol/MapBrowserEventType.js","../src/ol/MapBrowserPointerEvent.js","../src/ol/pointer/EventType.js","../src/ol/pointer/EventSource.js","../src/ol/pointer/MouseSource.js","../src/ol/pointer/MsSource.js","../src/ol/pointer/NativeSource.js","../src/ol/pointer/PointerEvent.js","../src/ol/pointer/TouchSource.js","../src/ol/pointer/PointerEventHandler.js","../src/ol/MapBrowserEventHandler.js","../src/ol/MapEventType.js","../src/ol/MapProperty.js","../src/ol/structs/PriorityQueue.js","../src/ol/TileQueue.js","../src/ol/tilegrid/common.js","../src/ol/centerconstraint.js","../src/ol/rotationconstraint.js","../src/ol/ViewHint.js","../src/ol/ViewProperty.js","../src/ol/View.js","../src/ol/resolutionconstraint.js","../src/ol/layer/Property.js","../src/ol/layer/Base.js","../src/ol/source/State.js","../src/ol/layer/Group.js","../src/ol/size.js","../src/ol/PluggableMap.js","../src/ol/control/Control.js","../src/ol/layer/Layer.js","../src/ol/control/Attribution.js","../src/ol/control/Rotate.js","../src/ol/control/Zoom.js","../src/ol/control/util.js","../src/ol/interaction/Property.js","../src/ol/interaction/Interaction.js","../src/ol/interaction/DoubleClickZoom.js","../src/ol/events/condition.js","../src/ol/interaction/Pointer.js","../src/ol/interaction/DragPan.js","../src/ol/interaction/DragRotate.js","../src/ol/render/Box.js","../src/ol/interaction/DragBox.js","../src/ol/interaction/DragZoom.js","../src/ol/events/KeyCode.js","../src/ol/interaction/KeyboardPan.js","../src/ol/interaction/KeyboardZoom.js","../src/ol/interaction/MouseWheelZoom.js","../src/ol/interaction/PinchRotate.js","../src/ol/interaction/PinchZoom.js","../src/ol/interaction/DragAndDrop.js","../src/ol/interaction/DragRotateAndZoom.js","../src/ol/geom/Circle.js","../src/ol/geom/MultiLineString.js","../src/ol/geom/MultiPoint.js","../src/ol/geom/flat/center.js","../src/ol/geom/MultiPolygon.js","../src/ol/LayerType.js","../src/ol/layer/VectorRenderType.js","../src/ol/layer/Vector.js","../src/ol/format/FormatType.js","../src/ol/featureloader.js","../src/ol/loadingstrategy.js","../src/ol/source/Source.js","../src/ol/source/VectorEventType.js","../node_modules/quickselect/quickselect.js","../node_modules/rbush/index.js","../src/ol/structs/RBush.js","../src/ol/source/Vector.js","../src/ol/interaction/Draw.js","../src/ol/interaction/Extent.js","../src/ol/interaction/Modify.js","../src/ol/interaction/Select.js","../src/ol/interaction/Snap.js","../src/ol/interaction/Translate.js","../src/ol/interaction.js","../src/ol/reproj/common.js","../src/ol/ImageCanvas.js","../src/ol/render/Event.js","../src/ol/render/VectorContext.js","../src/ol/render/canvas/Immediate.js","../src/ol/style/IconImageCache.js","../src/ol/renderer/Map.js","../src/ol/renderer/canvas/Map.js","../src/ol/renderer/Layer.js","../src/ol/renderer/canvas/Layer.js","../src/ol/renderer/canvas/IntermediateCanvas.js","../src/ol/renderer/canvas/ImageLayer.js","../src/ol/TileRange.js","../src/ol/renderer/canvas/TileLayer.js","../src/ol/render/ReplayGroup.js","../src/ol/render/ReplayType.js","../src/ol/geom/flat/textpath.js","../src/ol/render/canvas/Instruction.js","../src/ol/render/replay.js","../src/ol/render/canvas/Replay.js","../src/ol/render/canvas/ImageReplay.js","../src/ol/render/canvas/LineStringReplay.js","../src/ol/render/canvas/PolygonReplay.js","../src/ol/geom/flat/straightchunk.js","../src/ol/render/canvas/TextReplay.js","../src/ol/render/canvas/ReplayGroup.js","../src/ol/renderer/vector.js","../src/ol/renderer/canvas/VectorLayer.js","../src/ol/layer/VectorTileRenderType.js","../src/ol/renderer/canvas/VectorTileLayer.js","../src/ol/Map.js","../src/ol/OverlayPositioning.js","../src/ol/Overlay.js","../src/ol/VectorTile.js","../src/ol/control/FullScreen.js","../src/ol/control/OverviewMap.js","../src/ol/control/ScaleLine.js","../src/ol/control/ZoomSlider.js","../src/ol/control/ZoomToExtent.js","../src/ol/webgl/Shader.js","../src/ol/webgl/Fragment.js","../src/ol/webgl/Vertex.js","../src/ol/render/webgl/circlereplay/defaultshader.js","../src/ol/render/webgl/circlereplay/defaultshader/Locations.js","../src/ol/vec/mat4.js","../src/ol/render/webgl/Replay.js","../src/ol/render/webgl.js","../src/ol/webgl/Buffer.js","../src/ol/render/webgl/CircleReplay.js","../src/ol/render/webgl/texturereplay/defaultshader.js","../src/ol/render/webgl/texturereplay/defaultshader/Locations.js","../src/ol/webgl/ContextEventType.js","../src/ol/webgl/Context.js","../src/ol/render/webgl/TextureReplay.js","../src/ol/render/webgl/ImageReplay.js","../src/ol/geom/flat/topology.js","../src/ol/render/webgl/linestringreplay/defaultshader.js","../src/ol/render/webgl/linestringreplay/defaultshader/Locations.js","../src/ol/render/webgl/LineStringReplay.js","../src/ol/render/webgl/polygonreplay/defaultshader.js","../src/ol/render/webgl/polygonreplay/defaultshader/Locations.js","../src/ol/structs/LinkedList.js","../src/ol/render/webgl/PolygonReplay.js","../src/ol/style/Atlas.js","../src/ol/style/AtlasManager.js","../src/ol/render/webgl/TextReplay.js","../src/ol/render/webgl/ReplayGroup.js","../src/ol/render/webgl/Immediate.js","../src/ol/renderer/webgl/defaultmapshader.js","../src/ol/renderer/webgl/defaultmapshader/Locations.js","../src/ol/renderer/webgl/Layer.js","../src/ol/renderer/webgl/ImageLayer.js","../src/ol/renderer/webgl/Map.js","../src/ol/renderer/webgl/tilelayershader.js","../src/ol/renderer/webgl/tilelayershader/Locations.js","../src/ol/renderer/webgl/TileLayer.js","../src/ol/renderer/webgl/VectorLayer.js","../src/ol/WebGLMap.js","../src/ol/control/MousePosition.js","../src/ol/format/Feature.js","../src/ol/format/JSONFeature.js","../src/ol/format/EsriJSON.js","../src/ol/xml.js","../src/ol/format/XMLFeature.js","../src/ol/format/GMLBase.js","../src/ol/format/xsd.js","../src/ol/format/GML3.js","../src/ol/format/GML.js","../src/ol/format/GML2.js","../src/ol/format/GPX.js","../src/ol/geom/GeometryCollection.js","../src/ol/format/GeoJSON.js","../src/ol/format/TextFeature.js","../src/ol/format/IGC.js","../src/ol/style/IconAnchorUnits.js","../src/ol/style/IconImage.js","../src/ol/format/KML.js","../src/ol/style/IconOrigin.js","../src/ol/style/Icon.js","../node_modules/ieee754/index.js","../node_modules/pbf/index.js","../src/ol/render/Feature.js","../src/ol/format/MVT.js","../src/ol/format/OSMXML.js","../src/ol/geom/flat/flip.js","../src/ol/format/Polyline.js","../src/ol/format/TopoJSON.js","../src/ol/format/filter/Filter.js","../src/ol/format/filter/LogicalNary.js","../src/ol/format/filter/And.js","../src/ol/format/filter/Bbox.js","../src/ol/format/filter/Spatial.js","../src/ol/format/filter/Contains.js","../src/ol/format/filter/Comparison.js","../src/ol/format/filter/During.js","../src/ol/format/filter/ComparisonBinary.js","../src/ol/format/filter/EqualTo.js","../src/ol/format/filter/GreaterThan.js","../src/ol/format/filter/GreaterThanOrEqualTo.js","../src/ol/format/filter/Intersects.js","../src/ol/format/filter/IsBetween.js","../src/ol/format/filter/IsLike.js","../src/ol/format/filter/IsNull.js","../src/ol/format/filter/LessThan.js","../src/ol/format/filter/LessThanOrEqualTo.js","../src/ol/format/filter/Not.js","../src/ol/format/filter/NotEqualTo.js","../src/ol/format/filter/Or.js","../src/ol/format/filter/Within.js","../src/ol/format/filter.js","../src/ol/format/WFS.js","../src/ol/format/WKT.js","../src/ol/format/XLink.js","../src/ol/format/XML.js","../src/ol/format/WMSCapabilities.js","../src/ol/format/WMSGetFeatureInfo.js","../src/ol/format/OWS.js","../src/ol/format/WMTSCapabilities.js","../src/ol/layer/Heatmap.js","../src/ol/layer/Image.js","../src/ol/layer/TileProperty.js","../src/ol/layer/Tile.js","../src/ol/layer/VectorTile.js","../src/ol/tilecoord.js","../src/ol/tileurlfunction.js","../src/ol/net.js","../src/ol/TileCache.js","../src/ol/reproj.js","../src/ol/reproj/Triangulation.js","../src/ol/reproj/Tile.js","../src/ol/tilegrid/TileGrid.js","../src/ol/tilegrid.js","../src/ol/source/Tile.js","../src/ol/source/TileEventType.js","../src/ol/source/UrlTile.js","../src/ol/source/TileImage.js","../src/ol/source/BingMaps.js","../src/ol/source/XYZ.js","../src/ol/source/CartoDB.js","../src/ol/source/Cluster.js","../src/ol/reproj/Image.js","../src/ol/source/Image.js","../src/ol/uri.js","../src/ol/source/ImageArcGISRest.js","../src/ol/source/ImageCanvas.js","../src/ol/source/ImageMapGuide.js","../src/ol/source/ImageStatic.js","../src/ol/source/common.js","../src/ol/source/WMSServerType.js","../src/ol/source/ImageWMS.js","../src/ol/source/OSM.js","../node_modules/pixelworks/lib/util.js","../node_modules/pixelworks/lib/processor.js","../src/ol/source/Raster.js","../src/ol/source/Stamen.js","../src/ol/source/TileArcGISRest.js","../src/ol/source/TileDebug.js","../src/ol/source/TileJSON.js","../src/ol/source/TileWMS.js","../src/ol/source/UTFGrid.js","../src/ol/VectorImageTile.js","../src/ol/source/VectorTile.js","../src/ol/source/WMTSRequestEncoding.js","../src/ol/tilegrid/WMTS.js","../src/ol/source/WMTS.js","../src/ol/source/Zoomify.js","../src/index.js","../src/ol/proj/proj4.js","../src/ol/render.js"],"sourcesContent":["/**\n * @module ol/util\n */\n\n/**\n * Inherit the prototype methods from one constructor into another.\n *\n * Usage:\n *\n * function ParentClass(a, b) { }\n * ParentClass.prototype.foo = function(a) { }\n *\n * function ChildClass(a, b, c) {\n * // Call parent constructor\n * ParentClass.call(this, a, b);\n * }\n * inherits(ChildClass, ParentClass);\n *\n * var child = new ChildClass('a', 'b', 'see');\n * child.foo(); // This works.\n *\n * @param {!Function} childCtor Child constructor.\n * @param {!Function} parentCtor Parent constructor.\n * @function module:ol.inherits\n * @api\n */\nexport function inherits(childCtor, parentCtor) {\n childCtor.prototype = Object.create(parentCtor.prototype);\n childCtor.prototype.constructor = childCtor;\n}\n\n/**\n * Counter for getUid.\n * @type {number}\n * @private\n */\nlet uidCounter_ = 0;\n\n/**\n * Gets a unique ID for an object. This mutates the object so that further calls\n * with the same object as a parameter returns the same value. Unique IDs are generated\n * as a strictly increasing sequence. Adapted from goog.getUid.\n *\n * @param {Object} obj The object to get the unique ID for.\n * @return {number} The unique ID for the object.\n */\nexport function getUid(obj) {\n return obj.ol_uid || (obj.ol_uid = ++uidCounter_);\n}\n\n/**\n * OpenLayers version.\n * @type {string}\n */\nexport const VERSION = '5.0.3';\n","/**\n * @module ol/AssertionError\n */\nimport {VERSION, inherits} from './util.js';\n\n/**\n * Error object thrown when an assertion failed. This is an ECMA-262 Error,\n * extended with a `code` property.\n * @see {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error}\n * @constructor\n * @extends {Error}\n * @param {number} code Error code.\n */\nconst AssertionError = function(code) {\n\n const path = VERSION.split('-')[0];\n\n /**\n * @type {string}\n */\n this.message = 'Assertion failed. See https://openlayers.org/en/' + path +\n '/doc/errors/#' + code + ' for details.';\n\n /**\n * Error code. The meaning of the code can be found on\n * {@link https://openlayers.org/en/latest/doc/errors/} (replace `latest` with\n * the version found in the OpenLayers script's header comment if a version\n * other than the latest is used).\n * @type {number}\n * @api\n */\n this.code = code;\n\n this.name = 'AssertionError';\n\n};\n\ninherits(AssertionError, Error);\n\nexport default AssertionError;\n","/**\n * @module ol/CollectionEventType\n */\n\n/**\n * @enum {string}\n */\nexport default {\n /**\n * Triggered when an item is added to the collection.\n * @event module:ol/Collection~CollectionEvent#add\n * @api\n */\n ADD: 'add',\n /**\n * Triggered when an item is removed from the collection.\n * @event module:ol/Collection~CollectionEvent#remove\n * @api\n */\n REMOVE: 'remove'\n};\n","/**\n * @module ol/ObjectEventType\n */\n\n/**\n * @enum {string}\n */\nexport default {\n /**\n * Triggered when a property is changed.\n * @event module:ol/Object~ObjectEvent#propertychange\n * @api\n */\n PROPERTYCHANGE: 'propertychange'\n};\n","/**\n * @module ol/obj\n */\n\n\n/**\n * Polyfill for Object.assign(). Assigns enumerable and own properties from\n * one or more source objects to a target object.\n *\n * @see https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Object/assign\n * @param {!Object} target The target object.\n * @param {...Object} var_sources The source object(s).\n * @return {!Object} The modified target object.\n */\nexport const assign = (typeof Object.assign === 'function') ? Object.assign : function(target, var_sources) {\n if (target === undefined || target === null) {\n throw new TypeError('Cannot convert undefined or null to object');\n }\n\n const output = Object(target);\n for (let i = 1, ii = arguments.length; i < ii; ++i) {\n const source = arguments[i];\n if (source !== undefined && source !== null) {\n for (const key in source) {\n if (source.hasOwnProperty(key)) {\n output[key] = source[key];\n }\n }\n }\n }\n return output;\n};\n\n\n/**\n * Removes all properties from an object.\n * @param {Object} object The object to clear.\n */\nexport function clear(object) {\n for (const property in object) {\n delete object[property];\n }\n}\n\n\n/**\n * Get an array of property values from an object.\n * @param {Object} object The object from which to get the values.\n * @return {!Array} The property values.\n * @template K,V\n */\nexport function getValues(object) {\n const values = [];\n for (const property in object) {\n values.push(object[property]);\n }\n return values;\n}\n\n\n/**\n * Determine if an object has any properties.\n * @param {Object} object The object to check.\n * @return {boolean} The object is empty.\n */\nexport function isEmpty(object) {\n let property;\n for (property in object) {\n return false;\n }\n return !property;\n}\n","/**\n * @module ol/events\n */\nimport {clear} from './obj.js';\n\n\n/**\n * Key to use with {@link module:ol/Observable~Observable#unByKey}.\n * @typedef {Object} EventsKey\n * @property {Object} [bindTo]\n * @property {module:ol/events~ListenerFunction} [boundListener]\n * @property {boolean} callOnce\n * @property {number} [deleteIndex]\n * @property {module:ol/events~ListenerFunction} listener\n * @property {EventTarget|module:ol/events/EventTarget} target\n * @property {string} type\n * @api\n */\n\n\n/**\n * Listener function. This function is called with an event object as argument.\n * When the function returns `false`, event propagation will stop.\n *\n * @typedef {function(module:ol/events/Event)|function(module:ol/events/Event): boolean} ListenerFunction\n * @api\n */\n\n\n/**\n * @param {module:ol/events~EventsKey} listenerObj Listener object.\n * @return {module:ol/events~ListenerFunction} Bound listener.\n */\nexport function bindListener(listenerObj) {\n const boundListener = function(evt) {\n const listener = listenerObj.listener;\n const bindTo = listenerObj.bindTo || listenerObj.target;\n if (listenerObj.callOnce) {\n unlistenByKey(listenerObj);\n }\n return listener.call(bindTo, evt);\n };\n listenerObj.boundListener = boundListener;\n return boundListener;\n}\n\n\n/**\n * Finds the matching {@link module:ol/events~EventsKey} in the given listener\n * array.\n *\n * @param {!Array} listeners Array of listeners.\n * @param {!Function} listener The listener function.\n * @param {Object=} opt_this The `this` value inside the listener.\n * @param {boolean=} opt_setDeleteIndex Set the deleteIndex on the matching\n * listener, for {@link module:ol/events~unlistenByKey}.\n * @return {module:ol/events~EventsKey|undefined} The matching listener object.\n */\nexport function findListener(listeners, listener, opt_this, opt_setDeleteIndex) {\n let listenerObj;\n for (let i = 0, ii = listeners.length; i < ii; ++i) {\n listenerObj = listeners[i];\n if (listenerObj.listener === listener &&\n listenerObj.bindTo === opt_this) {\n if (opt_setDeleteIndex) {\n listenerObj.deleteIndex = i;\n }\n return listenerObj;\n }\n }\n return undefined;\n}\n\n\n/**\n * @param {module:ol/events/EventTarget~EventTargetLike} target Target.\n * @param {string} type Type.\n * @return {Array.|undefined} Listeners.\n */\nexport function getListeners(target, type) {\n const listenerMap = target.ol_lm;\n return listenerMap ? listenerMap[type] : undefined;\n}\n\n\n/**\n * Get the lookup of listeners. If one does not exist on the target, it is\n * created.\n * @param {module:ol/events/EventTarget~EventTargetLike} target Target.\n * @return {!Object.>} Map of\n * listeners by event type.\n */\nfunction getListenerMap(target) {\n let listenerMap = target.ol_lm;\n if (!listenerMap) {\n listenerMap = target.ol_lm = {};\n }\n return listenerMap;\n}\n\n\n/**\n * Clean up all listener objects of the given type. All properties on the\n * listener objects will be removed, and if no listeners remain in the listener\n * map, it will be removed from the target.\n * @param {module:ol/events/EventTarget~EventTargetLike} target Target.\n * @param {string} type Type.\n */\nfunction removeListeners(target, type) {\n const listeners = getListeners(target, type);\n if (listeners) {\n for (let i = 0, ii = listeners.length; i < ii; ++i) {\n target.removeEventListener(type, listeners[i].boundListener);\n clear(listeners[i]);\n }\n listeners.length = 0;\n const listenerMap = target.ol_lm;\n if (listenerMap) {\n delete listenerMap[type];\n if (Object.keys(listenerMap).length === 0) {\n delete target.ol_lm;\n }\n }\n }\n}\n\n\n/**\n * Registers an event listener on an event target. Inspired by\n * {@link https://google.github.io/closure-library/api/source/closure/goog/events/events.js.src.html}\n *\n * This function efficiently binds a `listener` to a `this` object, and returns\n * a key for use with {@link module:ol/events~unlistenByKey}.\n *\n * @param {module:ol/events/EventTarget~EventTargetLike} target Event target.\n * @param {string} type Event type.\n * @param {module:ol/events~ListenerFunction} listener Listener.\n * @param {Object=} opt_this Object referenced by the `this` keyword in the\n * listener. Default is the `target`.\n * @param {boolean=} opt_once If true, add the listener as one-off listener.\n * @return {module:ol/events~EventsKey} Unique key for the listener.\n */\nexport function listen(target, type, listener, opt_this, opt_once) {\n const listenerMap = getListenerMap(target);\n let listeners = listenerMap[type];\n if (!listeners) {\n listeners = listenerMap[type] = [];\n }\n let listenerObj = findListener(listeners, listener, opt_this, false);\n if (listenerObj) {\n if (!opt_once) {\n // Turn one-off listener into a permanent one.\n listenerObj.callOnce = false;\n }\n } else {\n listenerObj = /** @type {module:ol/events~EventsKey} */ ({\n bindTo: opt_this,\n callOnce: !!opt_once,\n listener: listener,\n target: target,\n type: type\n });\n target.addEventListener(type, bindListener(listenerObj));\n listeners.push(listenerObj);\n }\n\n return listenerObj;\n}\n\n\n/**\n * Registers a one-off event listener on an event target. Inspired by\n * {@link https://google.github.io/closure-library/api/source/closure/goog/events/events.js.src.html}\n *\n * This function efficiently binds a `listener` as self-unregistering listener\n * to a `this` object, and returns a key for use with\n * {@link module:ol/events~unlistenByKey} in case the listener needs to be\n * unregistered before it is called.\n *\n * When {@link module:ol/events~listen} is called with the same arguments after this\n * function, the self-unregistering listener will be turned into a permanent\n * listener.\n *\n * @param {module:ol/events/EventTarget~EventTargetLike} target Event target.\n * @param {string} type Event type.\n * @param {module:ol/events~ListenerFunction} listener Listener.\n * @param {Object=} opt_this Object referenced by the `this` keyword in the\n * listener. Default is the `target`.\n * @return {module:ol/events~EventsKey} Key for unlistenByKey.\n */\nexport function listenOnce(target, type, listener, opt_this) {\n return listen(target, type, listener, opt_this, true);\n}\n\n\n/**\n * Unregisters an event listener on an event target. Inspired by\n * {@link https://google.github.io/closure-library/api/source/closure/goog/events/events.js.src.html}\n *\n * To return a listener, this function needs to be called with the exact same\n * arguments that were used for a previous {@link module:ol/events~listen} call.\n *\n * @param {module:ol/events/EventTarget~EventTargetLike} target Event target.\n * @param {string} type Event type.\n * @param {module:ol/events~ListenerFunction} listener Listener.\n * @param {Object=} opt_this Object referenced by the `this` keyword in the\n * listener. Default is the `target`.\n */\nexport function unlisten(target, type, listener, opt_this) {\n const listeners = getListeners(target, type);\n if (listeners) {\n const listenerObj = findListener(listeners, listener, opt_this, true);\n if (listenerObj) {\n unlistenByKey(listenerObj);\n }\n }\n}\n\n\n/**\n * Unregisters event listeners on an event target. Inspired by\n * {@link https://google.github.io/closure-library/api/source/closure/goog/events/events.js.src.html}\n *\n * The argument passed to this function is the key returned from\n * {@link module:ol/events~listen} or {@link module:ol/events~listenOnce}.\n *\n * @param {module:ol/events~EventsKey} key The key.\n */\nexport function unlistenByKey(key) {\n if (key && key.target) {\n key.target.removeEventListener(key.type, key.boundListener);\n const listeners = getListeners(key.target, key.type);\n if (listeners) {\n const i = 'deleteIndex' in key ? key.deleteIndex : listeners.indexOf(key);\n if (i !== -1) {\n listeners.splice(i, 1);\n }\n if (listeners.length === 0) {\n removeListeners(key.target, key.type);\n }\n }\n clear(key);\n }\n}\n\n\n/**\n * Unregisters all event listeners on an event target. Inspired by\n * {@link https://google.github.io/closure-library/api/source/closure/goog/events/events.js.src.html}\n *\n * @param {module:ol/events/EventTarget~EventTargetLike} target Target.\n */\nexport function unlistenAll(target) {\n const listenerMap = getListenerMap(target);\n for (const type in listenerMap) {\n removeListeners(target, type);\n }\n}\n","/**\n * @module ol/functions\n */\n\n/**\n * Always returns true.\n * @returns {boolean} true.\n */\nexport function TRUE() {\n return true;\n}\n\n/**\n * Always returns false.\n * @returns {boolean} false.\n */\nexport function FALSE() {\n return false;\n}\n\n/**\n * A reusable function, used e.g. as a default for callbacks.\n *\n * @return {undefined} Nothing.\n */\nexport function UNDEFINED() {}\n","/**\n * @module ol/Disposable\n */\nimport {UNDEFINED} from './functions.js';\n\n/**\n * Objects that need to clean up after themselves.\n * @constructor\n */\nconst Disposable = function() {};\n\n/**\n * The object has already been disposed.\n * @type {boolean}\n * @private\n */\nDisposable.prototype.disposed_ = false;\n\n/**\n * Clean up.\n */\nDisposable.prototype.dispose = function() {\n if (!this.disposed_) {\n this.disposed_ = true;\n this.disposeInternal();\n }\n};\n\n/**\n * Extension point for disposable objects.\n * @protected\n */\nDisposable.prototype.disposeInternal = UNDEFINED;\nexport default Disposable;\n","/**\n * @module ol/events/Event\n */\n/**\n * @classdesc\n * Stripped down implementation of the W3C DOM Level 2 Event interface.\n * @see {@link https://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-interface}\n *\n * This implementation only provides `type` and `target` properties, and\n * `stopPropagation` and `preventDefault` methods. It is meant as base class\n * for higher level events defined in the library, and works with\n * {@link module:ol/events/EventTarget~EventTarget}.\n *\n * @constructor\n * @param {string} type Type.\n */\nconst Event = function(type) {\n\n /**\n * @type {boolean}\n */\n this.propagationStopped;\n\n /**\n * The event type.\n * @type {string}\n * @api\n */\n this.type = type;\n\n /**\n * The event target.\n * @type {Object}\n * @api\n */\n this.target = null;\n\n};\n\n\n/**\n * Stop event propagation.\n * @function\n * @api\n */\nEvent.prototype.preventDefault =\n\n /**\n * Stop event propagation.\n * @function\n * @api\n */\n Event.prototype.stopPropagation = function() {\n this.propagationStopped = true;\n };\n\n\n/**\n * @param {Event|module:ol/events/Event} evt Event\n */\nexport function stopPropagation(evt) {\n evt.stopPropagation();\n}\n\n\n/**\n * @param {Event|module:ol/events/Event} evt Event\n */\nexport function preventDefault(evt) {\n evt.preventDefault();\n}\n\nexport default Event;\n","/**\n * @module ol/events/EventTarget\n */\nimport {inherits} from '../util.js';\nimport Disposable from '../Disposable.js';\nimport {unlistenAll} from '../events.js';\nimport {UNDEFINED} from '../functions.js';\nimport Event from '../events/Event.js';\n\n\n/**\n * @typedef {EventTarget|module:ol/events/EventTarget} EventTargetLike\n */\n\n\n/**\n * @classdesc\n * A simplified implementation of the W3C DOM Level 2 EventTarget interface.\n * @see {@link https://www.w3.org/TR/2000/REC-DOM-Level-2-Events-20001113/events.html#Events-EventTarget}\n *\n * There are two important simplifications compared to the specification:\n *\n * 1. The handling of `useCapture` in `addEventListener` and\n * `removeEventListener`. There is no real capture model.\n * 2. The handling of `stopPropagation` and `preventDefault` on `dispatchEvent`.\n * There is no event target hierarchy. When a listener calls\n * `stopPropagation` or `preventDefault` on an event object, it means that no\n * more listeners after this one will be called. Same as when the listener\n * returns false.\n *\n * @constructor\n * @extends {module:ol/Disposable}\n */\nconst EventTarget = function() {\n\n Disposable.call(this);\n\n /**\n * @private\n * @type {!Object.}\n */\n this.pendingRemovals_ = {};\n\n /**\n * @private\n * @type {!Object.}\n */\n this.dispatching_ = {};\n\n /**\n * @private\n * @type {!Object.>}\n */\n this.listeners_ = {};\n\n};\n\ninherits(EventTarget, Disposable);\n\n\n/**\n * @param {string} type Type.\n * @param {module:ol/events~ListenerFunction} listener Listener.\n */\nEventTarget.prototype.addEventListener = function(type, listener) {\n let listeners = this.listeners_[type];\n if (!listeners) {\n listeners = this.listeners_[type] = [];\n }\n if (listeners.indexOf(listener) === -1) {\n listeners.push(listener);\n }\n};\n\n\n/**\n * @param {{type: string,\n * target: (EventTarget|module:ol/events/EventTarget|undefined)}|module:ol/events/Event|\n * string} event Event or event type.\n * @return {boolean|undefined} `false` if anyone called preventDefault on the\n * event object or if any of the listeners returned false.\n */\nEventTarget.prototype.dispatchEvent = function(event) {\n const evt = typeof event === 'string' ? new Event(event) : event;\n const type = evt.type;\n evt.target = this;\n const listeners = this.listeners_[type];\n let propagate;\n if (listeners) {\n if (!(type in this.dispatching_)) {\n this.dispatching_[type] = 0;\n this.pendingRemovals_[type] = 0;\n }\n ++this.dispatching_[type];\n for (let i = 0, ii = listeners.length; i < ii; ++i) {\n if (listeners[i].call(this, evt) === false || evt.propagationStopped) {\n propagate = false;\n break;\n }\n }\n --this.dispatching_[type];\n if (this.dispatching_[type] === 0) {\n let pendingRemovals = this.pendingRemovals_[type];\n delete this.pendingRemovals_[type];\n while (pendingRemovals--) {\n this.removeEventListener(type, UNDEFINED);\n }\n delete this.dispatching_[type];\n }\n return propagate;\n }\n};\n\n\n/**\n * @inheritDoc\n */\nEventTarget.prototype.disposeInternal = function() {\n unlistenAll(this);\n};\n\n\n/**\n * Get the listeners for a specified event type. Listeners are returned in the\n * order that they will be called in.\n *\n * @param {string} type Type.\n * @return {Array.} Listeners.\n */\nEventTarget.prototype.getListeners = function(type) {\n return this.listeners_[type];\n};\n\n\n/**\n * @param {string=} opt_type Type. If not provided,\n * `true` will be returned if this EventTarget has any listeners.\n * @return {boolean} Has listeners.\n */\nEventTarget.prototype.hasListener = function(opt_type) {\n return opt_type ?\n opt_type in this.listeners_ :\n Object.keys(this.listeners_).length > 0;\n};\n\n\n/**\n * @param {string} type Type.\n * @param {module:ol/events~ListenerFunction} listener Listener.\n */\nEventTarget.prototype.removeEventListener = function(type, listener) {\n const listeners = this.listeners_[type];\n if (listeners) {\n const index = listeners.indexOf(listener);\n if (type in this.pendingRemovals_) {\n // make listener a no-op, and remove later in #dispatchEvent()\n listeners[index] = UNDEFINED;\n ++this.pendingRemovals_[type];\n } else {\n listeners.splice(index, 1);\n if (listeners.length === 0) {\n delete this.listeners_[type];\n }\n }\n }\n};\nexport default EventTarget;\n","/**\n * @module ol/events/EventType\n */\n\n/**\n * @enum {string}\n * @const\n */\nexport default {\n /**\n * Generic change event. Triggered when the revision counter is increased.\n * @event module:ol/events/Event~Event#change\n * @api\n */\n CHANGE: 'change',\n\n CLEAR: 'clear',\n CONTEXTMENU: 'contextmenu',\n CLICK: 'click',\n DBLCLICK: 'dblclick',\n DRAGENTER: 'dragenter',\n DRAGOVER: 'dragover',\n DROP: 'drop',\n ERROR: 'error',\n KEYDOWN: 'keydown',\n KEYPRESS: 'keypress',\n LOAD: 'load',\n MOUSEDOWN: 'mousedown',\n MOUSEMOVE: 'mousemove',\n MOUSEOUT: 'mouseout',\n MOUSEUP: 'mouseup',\n MOUSEWHEEL: 'mousewheel',\n MSPOINTERDOWN: 'MSPointerDown',\n RESIZE: 'resize',\n TOUCHSTART: 'touchstart',\n TOUCHMOVE: 'touchmove',\n TOUCHEND: 'touchend',\n WHEEL: 'wheel'\n};\n","/**\n * @module ol/Observable\n */\nimport {inherits} from './util.js';\nimport {listen, unlistenByKey, unlisten, listenOnce} from './events.js';\nimport EventTarget from './events/EventTarget.js';\nimport EventType from './events/EventType.js';\n\n/**\n * @classdesc\n * Abstract base class; normally only used for creating subclasses and not\n * instantiated in apps.\n * An event target providing convenient methods for listener registration\n * and unregistration. A generic `change` event is always available through\n * {@link module:ol/Observable~Observable#changed}.\n *\n * @constructor\n * @extends {module:ol/events/EventTarget}\n * @fires module:ol/events/Event~Event\n * @struct\n * @api\n */\nconst Observable = function() {\n\n EventTarget.call(this);\n\n /**\n * @private\n * @type {number}\n */\n this.revision_ = 0;\n\n};\n\ninherits(Observable, EventTarget);\n\n\n/**\n * Removes an event listener using the key returned by `on()` or `once()`.\n * @param {module:ol/events~EventsKey|Array.} key The key returned by `on()`\n * or `once()` (or an array of keys).\n * @api\n */\nexport function unByKey(key) {\n if (Array.isArray(key)) {\n for (let i = 0, ii = key.length; i < ii; ++i) {\n unlistenByKey(key[i]);\n }\n } else {\n unlistenByKey(/** @type {module:ol/events~EventsKey} */ (key));\n }\n}\n\n\n/**\n * Increases the revision counter and dispatches a 'change' event.\n * @api\n */\nObservable.prototype.changed = function() {\n ++this.revision_;\n this.dispatchEvent(EventType.CHANGE);\n};\n\n\n/**\n * Dispatches an event and calls all listeners listening for events\n * of this type. The event parameter can either be a string or an\n * Object with a `type` property.\n *\n * @param {{type: string,\n * target: (EventTarget|module:ol/events/EventTarget|undefined)}|\n * module:ol/events/Event|string} event Event object.\n * @function\n * @api\n */\nObservable.prototype.dispatchEvent;\n\n\n/**\n * Get the version number for this object. Each time the object is modified,\n * its version number will be incremented.\n * @return {number} Revision.\n * @api\n */\nObservable.prototype.getRevision = function() {\n return this.revision_;\n};\n\n\n/**\n * Listen for a certain type of event.\n * @param {string|Array.} type The event type or array of event types.\n * @param {function(?): ?} listener The listener function.\n * @return {module:ol/events~EventsKey|Array.} Unique key for the listener. If\n * called with an array of event types as the first argument, the return\n * will be an array of keys.\n * @api\n */\nObservable.prototype.on = function(type, listener) {\n if (Array.isArray(type)) {\n const len = type.length;\n const keys = new Array(len);\n for (let i = 0; i < len; ++i) {\n keys[i] = listen(this, type[i], listener);\n }\n return keys;\n } else {\n return listen(this, /** @type {string} */ (type), listener);\n }\n};\n\n\n/**\n * Listen once for a certain type of event.\n * @param {string|Array.} type The event type or array of event types.\n * @param {function(?): ?} listener The listener function.\n * @return {module:ol/events~EventsKey|Array.} Unique key for the listener. If\n * called with an array of event types as the first argument, the return\n * will be an array of keys.\n * @api\n */\nObservable.prototype.once = function(type, listener) {\n if (Array.isArray(type)) {\n const len = type.length;\n const keys = new Array(len);\n for (let i = 0; i < len; ++i) {\n keys[i] = listenOnce(this, type[i], listener);\n }\n return keys;\n } else {\n return listenOnce(this, /** @type {string} */ (type), listener);\n }\n};\n\n\n/**\n * Unlisten for a certain type of event.\n * @param {string|Array.} type The event type or array of event types.\n * @param {function(?): ?} listener The listener function.\n * @api\n */\nObservable.prototype.un = function(type, listener) {\n if (Array.isArray(type)) {\n for (let i = 0, ii = type.length; i < ii; ++i) {\n unlisten(this, type[i], listener);\n }\n return;\n } else {\n unlisten(this, /** @type {string} */ (type), listener);\n }\n};\nexport default Observable;\n","/**\n * @module ol/Object\n */\nimport {getUid, inherits} from './util.js';\nimport ObjectEventType from './ObjectEventType.js';\nimport Observable from './Observable.js';\nimport Event from './events/Event.js';\nimport {assign} from './obj.js';\n\n\n/**\n * @classdesc\n * Events emitted by {@link module:ol/Object~BaseObject} instances are instances of\n * this type.\n *\n * @param {string} type The event type.\n * @param {string} key The property name.\n * @param {*} oldValue The old value for `key`.\n * @extends {module:ol/events/Event}\n * @constructor\n */\nconst ObjectEvent = function(type, key, oldValue) {\n Event.call(this, type);\n\n /**\n * The name of the property whose value is changing.\n * @type {string}\n * @api\n */\n this.key = key;\n\n /**\n * The old value. To get the new value use `e.target.get(e.key)` where\n * `e` is the event object.\n * @type {*}\n * @api\n */\n this.oldValue = oldValue;\n\n};\ninherits(ObjectEvent, Event);\n\n\n/**\n * @classdesc\n * Abstract base class; normally only used for creating subclasses and not\n * instantiated in apps.\n * Most non-trivial classes inherit from this.\n *\n * This extends {@link module:ol/Observable} with observable\n * properties, where each property is observable as well as the object as a\n * whole.\n *\n * Classes that inherit from this have pre-defined properties, to which you can\n * add your owns. The pre-defined properties are listed in this documentation as\n * 'Observable Properties', and have their own accessors; for example,\n * {@link module:ol/Map~Map} has a `target` property, accessed with\n * `getTarget()` and changed with `setTarget()`. Not all properties are however\n * settable. There are also general-purpose accessors `get()` and `set()`. For\n * example, `get('target')` is equivalent to `getTarget()`.\n *\n * The `set` accessors trigger a change event, and you can monitor this by\n * registering a listener. For example, {@link module:ol/View~View} has a\n * `center` property, so `view.on('change:center', function(evt) {...});` would\n * call the function whenever the value of the center property changes. Within\n * the function, `evt.target` would be the view, so `evt.target.getCenter()`\n * would return the new center.\n *\n * You can add your own observable properties with\n * `object.set('prop', 'value')`, and retrieve that with `object.get('prop')`.\n * You can listen for changes on that property value with\n * `object.on('change:prop', listener)`. You can get a list of all\n * properties with {@link module:ol/Object~BaseObject#getProperties}.\n *\n * Note that the observable properties are separate from standard JS properties.\n * You can, for example, give your map object a title with\n * `map.title='New title'` and with `map.set('title', 'Another title')`. The\n * first will be a `hasOwnProperty`; the second will appear in\n * `getProperties()`. Only the second is observable.\n *\n * Properties can be deleted by using the unset method. E.g.\n * object.unset('foo').\n *\n * @constructor\n * @extends {module:ol/Observable}\n * @param {Object.=} opt_values An object with key-value pairs.\n * @fires module:ol/Object~ObjectEvent\n * @api\n */\nconst BaseObject = function(opt_values) {\n Observable.call(this);\n\n // Call {@link module:ol~getUid} to ensure that the order of objects' ids is\n // the same as the order in which they were created. This also helps to\n // ensure that object properties are always added in the same order, which\n // helps many JavaScript engines generate faster code.\n getUid(this);\n\n /**\n * @private\n * @type {!Object.}\n */\n this.values_ = {};\n\n if (opt_values !== undefined) {\n this.setProperties(opt_values);\n }\n};\n\ninherits(BaseObject, Observable);\n\n\n/**\n * @type {Object.}\n */\nconst changeEventTypeCache = {};\n\n\n/**\n * @param {string} key Key name.\n * @return {string} Change name.\n */\nexport function getChangeEventType(key) {\n return changeEventTypeCache.hasOwnProperty(key) ?\n changeEventTypeCache[key] :\n (changeEventTypeCache[key] = 'change:' + key);\n}\n\n\n/**\n * Gets a value.\n * @param {string} key Key name.\n * @return {*} Value.\n * @api\n */\nBaseObject.prototype.get = function(key) {\n let value;\n if (this.values_.hasOwnProperty(key)) {\n value = this.values_[key];\n }\n return value;\n};\n\n\n/**\n * Get a list of object property names.\n * @return {Array.} List of property names.\n * @api\n */\nBaseObject.prototype.getKeys = function() {\n return Object.keys(this.values_);\n};\n\n\n/**\n * Get an object of all property names and values.\n * @return {Object.} Object.\n * @api\n */\nBaseObject.prototype.getProperties = function() {\n return assign({}, this.values_);\n};\n\n\n/**\n * @param {string} key Key name.\n * @param {*} oldValue Old value.\n */\nBaseObject.prototype.notify = function(key, oldValue) {\n let eventType;\n eventType = getChangeEventType(key);\n this.dispatchEvent(new ObjectEvent(eventType, key, oldValue));\n eventType = ObjectEventType.PROPERTYCHANGE;\n this.dispatchEvent(new ObjectEvent(eventType, key, oldValue));\n};\n\n\n/**\n * Sets a value.\n * @param {string} key Key name.\n * @param {*} value Value.\n * @param {boolean=} opt_silent Update without triggering an event.\n * @api\n */\nBaseObject.prototype.set = function(key, value, opt_silent) {\n if (opt_silent) {\n this.values_[key] = value;\n } else {\n const oldValue = this.values_[key];\n this.values_[key] = value;\n if (oldValue !== value) {\n this.notify(key, oldValue);\n }\n }\n};\n\n\n/**\n * Sets a collection of key-value pairs. Note that this changes any existing\n * properties and adds new ones (it does not remove any existing properties).\n * @param {Object.} values Values.\n * @param {boolean=} opt_silent Update without triggering an event.\n * @api\n */\nBaseObject.prototype.setProperties = function(values, opt_silent) {\n for (const key in values) {\n this.set(key, values[key], opt_silent);\n }\n};\n\n\n/**\n * Unsets a property.\n * @param {string} key Key name.\n * @param {boolean=} opt_silent Unset without triggering an event.\n * @api\n */\nBaseObject.prototype.unset = function(key, opt_silent) {\n if (key in this.values_) {\n const oldValue = this.values_[key];\n delete this.values_[key];\n if (!opt_silent) {\n this.notify(key, oldValue);\n }\n }\n};\n\n\nexport default BaseObject;\n","/**\n * @module ol/Collection\n */\nimport {inherits} from './util.js';\nimport AssertionError from './AssertionError.js';\nimport CollectionEventType from './CollectionEventType.js';\nimport BaseObject from './Object.js';\nimport Event from './events/Event.js';\n\n\n/**\n * @enum {string}\n * @private\n */\nconst Property = {\n LENGTH: 'length'\n};\n\n\n/**\n * @classdesc\n * Events emitted by {@link module:ol/Collection~Collection} instances are instances of this\n * type.\n *\n * @constructor\n * @extends {module:ol/events/Event}\n * @param {module:ol/CollectionEventType} type Type.\n * @param {*=} opt_element Element.\n */\nexport const CollectionEvent = function(type, opt_element) {\n\n Event.call(this, type);\n\n /**\n * The element that is added to or removed from the collection.\n * @type {*}\n * @api\n */\n this.element = opt_element;\n\n};\n\ninherits(CollectionEvent, Event);\n\n\n/**\n * @typedef {Object} Options\n * @property {boolean} [unique=false] Disallow the same item from being added to\n * the collection twice.\n */\n\n/**\n * @classdesc\n * An expanded version of standard JS Array, adding convenience methods for\n * manipulation. Add and remove changes to the Collection trigger a Collection\n * event. Note that this does not cover changes to the objects _within_ the\n * Collection; they trigger events on the appropriate object, not on the\n * Collection as a whole.\n *\n * @constructor\n * @extends {module:ol/Object}\n * @fires module:ol/Collection~CollectionEvent\n * @param {Array.=} opt_array Array.\n * @param {module:ol/Collection~Options=} opt_options Collection options.\n * @template T\n * @api\n */\nconst Collection = function(opt_array, opt_options) {\n\n BaseObject.call(this);\n\n const options = opt_options || {};\n\n /**\n * @private\n * @type {boolean}\n */\n this.unique_ = !!options.unique;\n\n /**\n * @private\n * @type {!Array.}\n */\n this.array_ = opt_array ? opt_array : [];\n\n if (this.unique_) {\n for (let i = 0, ii = this.array_.length; i < ii; ++i) {\n this.assertUnique_(this.array_[i], i);\n }\n }\n\n this.updateLength_();\n\n};\n\ninherits(Collection, BaseObject);\n\n\n/**\n * Remove all elements from the collection.\n * @api\n */\nCollection.prototype.clear = function() {\n while (this.getLength() > 0) {\n this.pop();\n }\n};\n\n\n/**\n * Add elements to the collection. This pushes each item in the provided array\n * to the end of the collection.\n * @param {!Array.} arr Array.\n * @return {module:ol/Collection.} This collection.\n * @api\n */\nCollection.prototype.extend = function(arr) {\n for (let i = 0, ii = arr.length; i < ii; ++i) {\n this.push(arr[i]);\n }\n return this;\n};\n\n\n/**\n * Iterate over each element, calling the provided callback.\n * @param {function(T, number, Array.): *} f The function to call\n * for every element. This function takes 3 arguments (the element, the\n * index and the array). The return value is ignored.\n * @api\n */\nCollection.prototype.forEach = function(f) {\n const array = this.array_;\n for (let i = 0, ii = array.length; i < ii; ++i) {\n f(array[i], i, array);\n }\n};\n\n\n/**\n * Get a reference to the underlying Array object. Warning: if the array\n * is mutated, no events will be dispatched by the collection, and the\n * collection's \"length\" property won't be in sync with the actual length\n * of the array.\n * @return {!Array.} Array.\n * @api\n */\nCollection.prototype.getArray = function() {\n return this.array_;\n};\n\n\n/**\n * Get the element at the provided index.\n * @param {number} index Index.\n * @return {T} Element.\n * @api\n */\nCollection.prototype.item = function(index) {\n return this.array_[index];\n};\n\n\n/**\n * Get the length of this collection.\n * @return {number} The length of the array.\n * @observable\n * @api\n */\nCollection.prototype.getLength = function() {\n return /** @type {number} */ (this.get(Property.LENGTH));\n};\n\n\n/**\n * Insert an element at the provided index.\n * @param {number} index Index.\n * @param {T} elem Element.\n * @api\n */\nCollection.prototype.insertAt = function(index, elem) {\n if (this.unique_) {\n this.assertUnique_(elem);\n }\n this.array_.splice(index, 0, elem);\n this.updateLength_();\n this.dispatchEvent(\n new CollectionEvent(CollectionEventType.ADD, elem));\n};\n\n\n/**\n * Remove the last element of the collection and return it.\n * Return `undefined` if the collection is empty.\n * @return {T|undefined} Element.\n * @api\n */\nCollection.prototype.pop = function() {\n return this.removeAt(this.getLength() - 1);\n};\n\n\n/**\n * Insert the provided element at the end of the collection.\n * @param {T} elem Element.\n * @return {number} New length of the collection.\n * @api\n */\nCollection.prototype.push = function(elem) {\n if (this.unique_) {\n this.assertUnique_(elem);\n }\n const n = this.getLength();\n this.insertAt(n, elem);\n return this.getLength();\n};\n\n\n/**\n * Remove the first occurrence of an element from the collection.\n * @param {T} elem Element.\n * @return {T|undefined} The removed element or undefined if none found.\n * @api\n */\nCollection.prototype.remove = function(elem) {\n const arr = this.array_;\n for (let i = 0, ii = arr.length; i < ii; ++i) {\n if (arr[i] === elem) {\n return this.removeAt(i);\n }\n }\n return undefined;\n};\n\n\n/**\n * Remove the element at the provided index and return it.\n * Return `undefined` if the collection does not contain this index.\n * @param {number} index Index.\n * @return {T|undefined} Value.\n * @api\n */\nCollection.prototype.removeAt = function(index) {\n const prev = this.array_[index];\n this.array_.splice(index, 1);\n this.updateLength_();\n this.dispatchEvent(new CollectionEvent(CollectionEventType.REMOVE, prev));\n return prev;\n};\n\n\n/**\n * Set the element at the provided index.\n * @param {number} index Index.\n * @param {T} elem Element.\n * @api\n */\nCollection.prototype.setAt = function(index, elem) {\n const n = this.getLength();\n if (index < n) {\n if (this.unique_) {\n this.assertUnique_(elem, index);\n }\n const prev = this.array_[index];\n this.array_[index] = elem;\n this.dispatchEvent(\n new CollectionEvent(CollectionEventType.REMOVE, prev));\n this.dispatchEvent(\n new CollectionEvent(CollectionEventType.ADD, elem));\n } else {\n for (let j = n; j < index; ++j) {\n this.insertAt(j, undefined);\n }\n this.insertAt(index, elem);\n }\n};\n\n\n/**\n * @private\n */\nCollection.prototype.updateLength_ = function() {\n this.set(Property.LENGTH, this.array_.length);\n};\n\n\n/**\n * @private\n * @param {T} elem Element.\n * @param {number=} opt_except Optional index to ignore.\n */\nCollection.prototype.assertUnique_ = function(elem, opt_except) {\n for (let i = 0, ii = this.array_.length; i < ii; ++i) {\n if (this.array_[i] === elem && i !== opt_except) {\n throw new AssertionError(58);\n }\n }\n};\n\nexport default Collection;\n","/**\n * @module ol/asserts\n */\nimport AssertionError from './AssertionError.js';\n\n/**\n * @param {*} assertion Assertion we expected to be truthy.\n * @param {number} errorCode Error code.\n */\nexport function assert(assertion, errorCode) {\n if (!assertion) {\n throw new AssertionError(errorCode);\n }\n}\n","/**\n * @module ol/extent/Corner\n */\n\n/**\n * Extent corner.\n * @enum {string}\n */\nexport default {\n BOTTOM_LEFT: 'bottom-left',\n BOTTOM_RIGHT: 'bottom-right',\n TOP_LEFT: 'top-left',\n TOP_RIGHT: 'top-right'\n};\n","/**\n * @module ol/extent/Relationship\n */\n\n/**\n * Relationship to an extent.\n * @enum {number}\n */\nexport default {\n UNKNOWN: 0,\n INTERSECTING: 1,\n ABOVE: 2,\n RIGHT: 4,\n BELOW: 8,\n LEFT: 16\n};\n","/**\n * @module ol/extent\n */\nimport {assert} from './asserts.js';\nimport Corner from './extent/Corner.js';\nimport Relationship from './extent/Relationship.js';\n\n\n/**\n * An array of numbers representing an extent: `[minx, miny, maxx, maxy]`.\n * @typedef {Array.} Extent\n * @api\n */\n\n/**\n * Build an extent that includes all given coordinates.\n *\n * @param {Array.} coordinates Coordinates.\n * @return {module:ol/extent~Extent} Bounding extent.\n * @api\n */\nexport function boundingExtent(coordinates) {\n const extent = createEmpty();\n for (let i = 0, ii = coordinates.length; i < ii; ++i) {\n extendCoordinate(extent, coordinates[i]);\n }\n return extent;\n}\n\n\n/**\n * @param {Array.} xs Xs.\n * @param {Array.} ys Ys.\n * @param {module:ol/extent~Extent=} opt_extent Destination extent.\n * @private\n * @return {module:ol/extent~Extent} Extent.\n */\nfunction _boundingExtentXYs(xs, ys, opt_extent) {\n const minX = Math.min.apply(null, xs);\n const minY = Math.min.apply(null, ys);\n const maxX = Math.max.apply(null, xs);\n const maxY = Math.max.apply(null, ys);\n return createOrUpdate(minX, minY, maxX, maxY, opt_extent);\n}\n\n\n/**\n * Return extent increased by the provided value.\n * @param {module:ol/extent~Extent} extent Extent.\n * @param {number} value The amount by which the extent should be buffered.\n * @param {module:ol/extent~Extent=} opt_extent Extent.\n * @return {module:ol/extent~Extent} Extent.\n * @api\n */\nexport function buffer(extent, value, opt_extent) {\n if (opt_extent) {\n opt_extent[0] = extent[0] - value;\n opt_extent[1] = extent[1] - value;\n opt_extent[2] = extent[2] + value;\n opt_extent[3] = extent[3] + value;\n return opt_extent;\n } else {\n return [\n extent[0] - value,\n extent[1] - value,\n extent[2] + value,\n extent[3] + value\n ];\n }\n}\n\n\n/**\n * Creates a clone of an extent.\n *\n * @param {module:ol/extent~Extent} extent Extent to clone.\n * @param {module:ol/extent~Extent=} opt_extent Extent.\n * @return {module:ol/extent~Extent} The clone.\n */\nexport function clone(extent, opt_extent) {\n if (opt_extent) {\n opt_extent[0] = extent[0];\n opt_extent[1] = extent[1];\n opt_extent[2] = extent[2];\n opt_extent[3] = extent[3];\n return opt_extent;\n } else {\n return extent.slice();\n }\n}\n\n\n/**\n * @param {module:ol/extent~Extent} extent Extent.\n * @param {number} x X.\n * @param {number} y Y.\n * @return {number} Closest squared distance.\n */\nexport function closestSquaredDistanceXY(extent, x, y) {\n let dx, dy;\n if (x < extent[0]) {\n dx = extent[0] - x;\n } else if (extent[2] < x) {\n dx = x - extent[2];\n } else {\n dx = 0;\n }\n if (y < extent[1]) {\n dy = extent[1] - y;\n } else if (extent[3] < y) {\n dy = y - extent[3];\n } else {\n dy = 0;\n }\n return dx * dx + dy * dy;\n}\n\n\n/**\n * Check if the passed coordinate is contained or on the edge of the extent.\n *\n * @param {module:ol/extent~Extent} extent Extent.\n * @param {module:ol/coordinate~Coordinate} coordinate Coordinate.\n * @return {boolean} The coordinate is contained in the extent.\n * @api\n */\nexport function containsCoordinate(extent, coordinate) {\n return containsXY(extent, coordinate[0], coordinate[1]);\n}\n\n\n/**\n * Check if one extent contains another.\n *\n * An extent is deemed contained if it lies completely within the other extent,\n * including if they share one or more edges.\n *\n * @param {module:ol/extent~Extent} extent1 Extent 1.\n * @param {module:ol/extent~Extent} extent2 Extent 2.\n * @return {boolean} The second extent is contained by or on the edge of the\n * first.\n * @api\n */\nexport function containsExtent(extent1, extent2) {\n return extent1[0] <= extent2[0] && extent2[2] <= extent1[2] &&\n extent1[1] <= extent2[1] && extent2[3] <= extent1[3];\n}\n\n\n/**\n * Check if the passed coordinate is contained or on the edge of the extent.\n *\n * @param {module:ol/extent~Extent} extent Extent.\n * @param {number} x X coordinate.\n * @param {number} y Y coordinate.\n * @return {boolean} The x, y values are contained in the extent.\n * @api\n */\nexport function containsXY(extent, x, y) {\n return extent[0] <= x && x <= extent[2] && extent[1] <= y && y <= extent[3];\n}\n\n\n/**\n * Get the relationship between a coordinate and extent.\n * @param {module:ol/extent~Extent} extent The extent.\n * @param {module:ol/coordinate~Coordinate} coordinate The coordinate.\n * @return {module:ol/extent/Relationship} The relationship (bitwise compare with\n * module:ol/extent/Relationship~Relationship).\n */\nexport function coordinateRelationship(extent, coordinate) {\n const minX = extent[0];\n const minY = extent[1];\n const maxX = extent[2];\n const maxY = extent[3];\n const x = coordinate[0];\n const y = coordinate[1];\n let relationship = Relationship.UNKNOWN;\n if (x < minX) {\n relationship = relationship | Relationship.LEFT;\n } else if (x > maxX) {\n relationship = relationship | Relationship.RIGHT;\n }\n if (y < minY) {\n relationship = relationship | Relationship.BELOW;\n } else if (y > maxY) {\n relationship = relationship | Relationship.ABOVE;\n }\n if (relationship === Relationship.UNKNOWN) {\n relationship = Relationship.INTERSECTING;\n }\n return relationship;\n}\n\n\n/**\n * Create an empty extent.\n * @return {module:ol/extent~Extent} Empty extent.\n * @api\n */\nexport function createEmpty() {\n return [Infinity, Infinity, -Infinity, -Infinity];\n}\n\n\n/**\n * Create a new extent or update the provided extent.\n * @param {number} minX Minimum X.\n * @param {number} minY Minimum Y.\n * @param {number} maxX Maximum X.\n * @param {number} maxY Maximum Y.\n * @param {module:ol/extent~Extent=} opt_extent Destination extent.\n * @return {module:ol/extent~Extent} Extent.\n */\nexport function createOrUpdate(minX, minY, maxX, maxY, opt_extent) {\n if (opt_extent) {\n opt_extent[0] = minX;\n opt_extent[1] = minY;\n opt_extent[2] = maxX;\n opt_extent[3] = maxY;\n return opt_extent;\n } else {\n return [minX, minY, maxX, maxY];\n }\n}\n\n\n/**\n * Create a new empty extent or make the provided one empty.\n * @param {module:ol/extent~Extent=} opt_extent Extent.\n * @return {module:ol/extent~Extent} Extent.\n */\nexport function createOrUpdateEmpty(opt_extent) {\n return createOrUpdate(\n Infinity, Infinity, -Infinity, -Infinity, opt_extent);\n}\n\n\n/**\n * @param {module:ol/coordinate~Coordinate} coordinate Coordinate.\n * @param {module:ol/extent~Extent=} opt_extent Extent.\n * @return {module:ol/extent~Extent} Extent.\n */\nexport function createOrUpdateFromCoordinate(coordinate, opt_extent) {\n const x = coordinate[0];\n const y = coordinate[1];\n return createOrUpdate(x, y, x, y, opt_extent);\n}\n\n\n/**\n * @param {Array.} coordinates Coordinates.\n * @param {module:ol/extent~Extent=} opt_extent Extent.\n * @return {module:ol/extent~Extent} Extent.\n */\nexport function createOrUpdateFromCoordinates(coordinates, opt_extent) {\n const extent = createOrUpdateEmpty(opt_extent);\n return extendCoordinates(extent, coordinates);\n}\n\n\n/**\n * @param {Array.} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {number} end End.\n * @param {number} stride Stride.\n * @param {module:ol/extent~Extent=} opt_extent Extent.\n * @return {module:ol/extent~Extent} Extent.\n */\nexport function createOrUpdateFromFlatCoordinates(flatCoordinates, offset, end, stride, opt_extent) {\n const extent = createOrUpdateEmpty(opt_extent);\n return extendFlatCoordinates(extent, flatCoordinates, offset, end, stride);\n}\n\n/**\n * @param {Array.>} rings Rings.\n * @param {module:ol/extent~Extent=} opt_extent Extent.\n * @return {module:ol/extent~Extent} Extent.\n */\nexport function createOrUpdateFromRings(rings, opt_extent) {\n const extent = createOrUpdateEmpty(opt_extent);\n return extendRings(extent, rings);\n}\n\n\n/**\n * Determine if two extents are equivalent.\n * @param {module:ol/extent~Extent} extent1 Extent 1.\n * @param {module:ol/extent~Extent} extent2 Extent 2.\n * @return {boolean} The two extents are equivalent.\n * @api\n */\nexport function equals(extent1, extent2) {\n return extent1[0] == extent2[0] && extent1[2] == extent2[2] &&\n extent1[1] == extent2[1] && extent1[3] == extent2[3];\n}\n\n\n/**\n * Modify an extent to include another extent.\n * @param {module:ol/extent~Extent} extent1 The extent to be modified.\n * @param {module:ol/extent~Extent} extent2 The extent that will be included in the first.\n * @return {module:ol/extent~Extent} A reference to the first (extended) extent.\n * @api\n */\nexport function extend(extent1, extent2) {\n if (extent2[0] < extent1[0]) {\n extent1[0] = extent2[0];\n }\n if (extent2[2] > extent1[2]) {\n extent1[2] = extent2[2];\n }\n if (extent2[1] < extent1[1]) {\n extent1[1] = extent2[1];\n }\n if (extent2[3] > extent1[3]) {\n extent1[3] = extent2[3];\n }\n return extent1;\n}\n\n\n/**\n * @param {module:ol/extent~Extent} extent Extent.\n * @param {module:ol/coordinate~Coordinate} coordinate Coordinate.\n */\nexport function extendCoordinate(extent, coordinate) {\n if (coordinate[0] < extent[0]) {\n extent[0] = coordinate[0];\n }\n if (coordinate[0] > extent[2]) {\n extent[2] = coordinate[0];\n }\n if (coordinate[1] < extent[1]) {\n extent[1] = coordinate[1];\n }\n if (coordinate[1] > extent[3]) {\n extent[3] = coordinate[1];\n }\n}\n\n\n/**\n * @param {module:ol/extent~Extent} extent Extent.\n * @param {Array.} coordinates Coordinates.\n * @return {module:ol/extent~Extent} Extent.\n */\nexport function extendCoordinates(extent, coordinates) {\n for (let i = 0, ii = coordinates.length; i < ii; ++i) {\n extendCoordinate(extent, coordinates[i]);\n }\n return extent;\n}\n\n\n/**\n * @param {module:ol/extent~Extent} extent Extent.\n * @param {Array.} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {number} end End.\n * @param {number} stride Stride.\n * @return {module:ol/extent~Extent} Extent.\n */\nexport function extendFlatCoordinates(extent, flatCoordinates, offset, end, stride) {\n for (; offset < end; offset += stride) {\n extendXY(extent, flatCoordinates[offset], flatCoordinates[offset + 1]);\n }\n return extent;\n}\n\n\n/**\n * @param {module:ol/extent~Extent} extent Extent.\n * @param {Array.>} rings Rings.\n * @return {module:ol/extent~Extent} Extent.\n */\nexport function extendRings(extent, rings) {\n for (let i = 0, ii = rings.length; i < ii; ++i) {\n extendCoordinates(extent, rings[i]);\n }\n return extent;\n}\n\n\n/**\n * @param {module:ol/extent~Extent} extent Extent.\n * @param {number} x X.\n * @param {number} y Y.\n */\nexport function extendXY(extent, x, y) {\n extent[0] = Math.min(extent[0], x);\n extent[1] = Math.min(extent[1], y);\n extent[2] = Math.max(extent[2], x);\n extent[3] = Math.max(extent[3], y);\n}\n\n\n/**\n * This function calls `callback` for each corner of the extent. If the\n * callback returns a truthy value the function returns that value\n * immediately. Otherwise the function returns `false`.\n * @param {module:ol/extent~Extent} extent Extent.\n * @param {function(this:T, module:ol/coordinate~Coordinate): S} callback Callback.\n * @param {T=} opt_this Value to use as `this` when executing `callback`.\n * @return {S|boolean} Value.\n * @template S, T\n */\nexport function forEachCorner(extent, callback, opt_this) {\n let val;\n val = callback.call(opt_this, getBottomLeft(extent));\n if (val) {\n return val;\n }\n val = callback.call(opt_this, getBottomRight(extent));\n if (val) {\n return val;\n }\n val = callback.call(opt_this, getTopRight(extent));\n if (val) {\n return val;\n }\n val = callback.call(opt_this, getTopLeft(extent));\n if (val) {\n return val;\n }\n return false;\n}\n\n\n/**\n * Get the size of an extent.\n * @param {module:ol/extent~Extent} extent Extent.\n * @return {number} Area.\n * @api\n */\nexport function getArea(extent) {\n let area = 0;\n if (!isEmpty(extent)) {\n area = getWidth(extent) * getHeight(extent);\n }\n return area;\n}\n\n\n/**\n * Get the bottom left coordinate of an extent.\n * @param {module:ol/extent~Extent} extent Extent.\n * @return {module:ol/coordinate~Coordinate} Bottom left coordinate.\n * @api\n */\nexport function getBottomLeft(extent) {\n return [extent[0], extent[1]];\n}\n\n\n/**\n * Get the bottom right coordinate of an extent.\n * @param {module:ol/extent~Extent} extent Extent.\n * @return {module:ol/coordinate~Coordinate} Bottom right coordinate.\n * @api\n */\nexport function getBottomRight(extent) {\n return [extent[2], extent[1]];\n}\n\n\n/**\n * Get the center coordinate of an extent.\n * @param {module:ol/extent~Extent} extent Extent.\n * @return {module:ol/coordinate~Coordinate} Center.\n * @api\n */\nexport function getCenter(extent) {\n return [(extent[0] + extent[2]) / 2, (extent[1] + extent[3]) / 2];\n}\n\n\n/**\n * Get a corner coordinate of an extent.\n * @param {module:ol/extent~Extent} extent Extent.\n * @param {module:ol/extent/Corner} corner Corner.\n * @return {module:ol/coordinate~Coordinate} Corner coordinate.\n */\nexport function getCorner(extent, corner) {\n let coordinate;\n if (corner === Corner.BOTTOM_LEFT) {\n coordinate = getBottomLeft(extent);\n } else if (corner === Corner.BOTTOM_RIGHT) {\n coordinate = getBottomRight(extent);\n } else if (corner === Corner.TOP_LEFT) {\n coordinate = getTopLeft(extent);\n } else if (corner === Corner.TOP_RIGHT) {\n coordinate = getTopRight(extent);\n } else {\n assert(false, 13); // Invalid corner\n }\n return (\n /** @type {!module:ol/coordinate~Coordinate} */ (coordinate)\n );\n}\n\n\n/**\n * @param {module:ol/extent~Extent} extent1 Extent 1.\n * @param {module:ol/extent~Extent} extent2 Extent 2.\n * @return {number} Enlarged area.\n */\nexport function getEnlargedArea(extent1, extent2) {\n const minX = Math.min(extent1[0], extent2[0]);\n const minY = Math.min(extent1[1], extent2[1]);\n const maxX = Math.max(extent1[2], extent2[2]);\n const maxY = Math.max(extent1[3], extent2[3]);\n return (maxX - minX) * (maxY - minY);\n}\n\n\n/**\n * @param {module:ol/coordinate~Coordinate} center Center.\n * @param {number} resolution Resolution.\n * @param {number} rotation Rotation.\n * @param {module:ol/size~Size} size Size.\n * @param {module:ol/extent~Extent=} opt_extent Destination extent.\n * @return {module:ol/extent~Extent} Extent.\n */\nexport function getForViewAndSize(center, resolution, rotation, size, opt_extent) {\n const dx = resolution * size[0] / 2;\n const dy = resolution * size[1] / 2;\n const cosRotation = Math.cos(rotation);\n const sinRotation = Math.sin(rotation);\n const xCos = dx * cosRotation;\n const xSin = dx * sinRotation;\n const yCos = dy * cosRotation;\n const ySin = dy * sinRotation;\n const x = center[0];\n const y = center[1];\n const x0 = x - xCos + ySin;\n const x1 = x - xCos - ySin;\n const x2 = x + xCos - ySin;\n const x3 = x + xCos + ySin;\n const y0 = y - xSin - yCos;\n const y1 = y - xSin + yCos;\n const y2 = y + xSin + yCos;\n const y3 = y + xSin - yCos;\n return createOrUpdate(\n Math.min(x0, x1, x2, x3), Math.min(y0, y1, y2, y3),\n Math.max(x0, x1, x2, x3), Math.max(y0, y1, y2, y3),\n opt_extent);\n}\n\n\n/**\n * Get the height of an extent.\n * @param {module:ol/extent~Extent} extent Extent.\n * @return {number} Height.\n * @api\n */\nexport function getHeight(extent) {\n return extent[3] - extent[1];\n}\n\n\n/**\n * @param {module:ol/extent~Extent} extent1 Extent 1.\n * @param {module:ol/extent~Extent} extent2 Extent 2.\n * @return {number} Intersection area.\n */\nexport function getIntersectionArea(extent1, extent2) {\n const intersection = getIntersection(extent1, extent2);\n return getArea(intersection);\n}\n\n\n/**\n * Get the intersection of two extents.\n * @param {module:ol/extent~Extent} extent1 Extent 1.\n * @param {module:ol/extent~Extent} extent2 Extent 2.\n * @param {module:ol/extent~Extent=} opt_extent Optional extent to populate with intersection.\n * @return {module:ol/extent~Extent} Intersecting extent.\n * @api\n */\nexport function getIntersection(extent1, extent2, opt_extent) {\n const intersection = opt_extent ? opt_extent : createEmpty();\n if (intersects(extent1, extent2)) {\n if (extent1[0] > extent2[0]) {\n intersection[0] = extent1[0];\n } else {\n intersection[0] = extent2[0];\n }\n if (extent1[1] > extent2[1]) {\n intersection[1] = extent1[1];\n } else {\n intersection[1] = extent2[1];\n }\n if (extent1[2] < extent2[2]) {\n intersection[2] = extent1[2];\n } else {\n intersection[2] = extent2[2];\n }\n if (extent1[3] < extent2[3]) {\n intersection[3] = extent1[3];\n } else {\n intersection[3] = extent2[3];\n }\n } else {\n createOrUpdateEmpty(intersection);\n }\n return intersection;\n}\n\n\n/**\n * @param {module:ol/extent~Extent} extent Extent.\n * @return {number} Margin.\n */\nexport function getMargin(extent) {\n return getWidth(extent) + getHeight(extent);\n}\n\n\n/**\n * Get the size (width, height) of an extent.\n * @param {module:ol/extent~Extent} extent The extent.\n * @return {module:ol/size~Size} The extent size.\n * @api\n */\nexport function getSize(extent) {\n return [extent[2] - extent[0], extent[3] - extent[1]];\n}\n\n\n/**\n * Get the top left coordinate of an extent.\n * @param {module:ol/extent~Extent} extent Extent.\n * @return {module:ol/coordinate~Coordinate} Top left coordinate.\n * @api\n */\nexport function getTopLeft(extent) {\n return [extent[0], extent[3]];\n}\n\n\n/**\n * Get the top right coordinate of an extent.\n * @param {module:ol/extent~Extent} extent Extent.\n * @return {module:ol/coordinate~Coordinate} Top right coordinate.\n * @api\n */\nexport function getTopRight(extent) {\n return [extent[2], extent[3]];\n}\n\n\n/**\n * Get the width of an extent.\n * @param {module:ol/extent~Extent} extent Extent.\n * @return {number} Width.\n * @api\n */\nexport function getWidth(extent) {\n return extent[2] - extent[0];\n}\n\n\n/**\n * Determine if one extent intersects another.\n * @param {module:ol/extent~Extent} extent1 Extent 1.\n * @param {module:ol/extent~Extent} extent2 Extent.\n * @return {boolean} The two extents intersect.\n * @api\n */\nexport function intersects(extent1, extent2) {\n return extent1[0] <= extent2[2] &&\n extent1[2] >= extent2[0] &&\n extent1[1] <= extent2[3] &&\n extent1[3] >= extent2[1];\n}\n\n\n/**\n * Determine if an extent is empty.\n * @param {module:ol/extent~Extent} extent Extent.\n * @return {boolean} Is empty.\n * @api\n */\nexport function isEmpty(extent) {\n return extent[2] < extent[0] || extent[3] < extent[1];\n}\n\n\n/**\n * @param {module:ol/extent~Extent} extent Extent.\n * @param {module:ol/extent~Extent=} opt_extent Extent.\n * @return {module:ol/extent~Extent} Extent.\n */\nexport function returnOrUpdate(extent, opt_extent) {\n if (opt_extent) {\n opt_extent[0] = extent[0];\n opt_extent[1] = extent[1];\n opt_extent[2] = extent[2];\n opt_extent[3] = extent[3];\n return opt_extent;\n } else {\n return extent;\n }\n}\n\n\n/**\n * @param {module:ol/extent~Extent} extent Extent.\n * @param {number} value Value.\n */\nexport function scaleFromCenter(extent, value) {\n const deltaX = ((extent[2] - extent[0]) / 2) * (value - 1);\n const deltaY = ((extent[3] - extent[1]) / 2) * (value - 1);\n extent[0] -= deltaX;\n extent[2] += deltaX;\n extent[1] -= deltaY;\n extent[3] += deltaY;\n}\n\n\n/**\n * Determine if the segment between two coordinates intersects (crosses,\n * touches, or is contained by) the provided extent.\n * @param {module:ol/extent~Extent} extent The extent.\n * @param {module:ol/coordinate~Coordinate} start Segment start coordinate.\n * @param {module:ol/coordinate~Coordinate} end Segment end coordinate.\n * @return {boolean} The segment intersects the extent.\n */\nexport function intersectsSegment(extent, start, end) {\n let intersects = false;\n const startRel = coordinateRelationship(extent, start);\n const endRel = coordinateRelationship(extent, end);\n if (startRel === Relationship.INTERSECTING ||\n endRel === Relationship.INTERSECTING) {\n intersects = true;\n } else {\n const minX = extent[0];\n const minY = extent[1];\n const maxX = extent[2];\n const maxY = extent[3];\n const startX = start[0];\n const startY = start[1];\n const endX = end[0];\n const endY = end[1];\n const slope = (endY - startY) / (endX - startX);\n let x, y;\n if (!!(endRel & Relationship.ABOVE) &&\n !(startRel & Relationship.ABOVE)) {\n // potentially intersects top\n x = endX - ((endY - maxY) / slope);\n intersects = x >= minX && x <= maxX;\n }\n if (!intersects && !!(endRel & Relationship.RIGHT) &&\n !(startRel & Relationship.RIGHT)) {\n // potentially intersects right\n y = endY - ((endX - maxX) * slope);\n intersects = y >= minY && y <= maxY;\n }\n if (!intersects && !!(endRel & Relationship.BELOW) &&\n !(startRel & Relationship.BELOW)) {\n // potentially intersects bottom\n x = endX - ((endY - minY) / slope);\n intersects = x >= minX && x <= maxX;\n }\n if (!intersects && !!(endRel & Relationship.LEFT) &&\n !(startRel & Relationship.LEFT)) {\n // potentially intersects left\n y = endY - ((endX - minX) * slope);\n intersects = y >= minY && y <= maxY;\n }\n\n }\n return intersects;\n}\n\n\n/**\n * Apply a transform function to the extent.\n * @param {module:ol/extent~Extent} extent Extent.\n * @param {module:ol/proj~TransformFunction} transformFn Transform function.\n * Called with `[minX, minY, maxX, maxY]` extent coordinates.\n * @param {module:ol/extent~Extent=} opt_extent Destination extent.\n * @return {module:ol/extent~Extent} Extent.\n * @api\n */\nexport function applyTransform(extent, transformFn, opt_extent) {\n const coordinates = [\n extent[0], extent[1],\n extent[0], extent[3],\n extent[2], extent[1],\n extent[2], extent[3]\n ];\n transformFn(coordinates, coordinates, 2);\n const xs = [coordinates[0], coordinates[2], coordinates[4], coordinates[6]];\n const ys = [coordinates[1], coordinates[3], coordinates[5], coordinates[7]];\n return _boundingExtentXYs(xs, ys, opt_extent);\n}\n","/**\n * @module ol/geom/flat/transform\n */\n\n\n/**\n * @param {Array.} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {number} end End.\n * @param {number} stride Stride.\n * @param {module:ol/transform~Transform} transform Transform.\n * @param {Array.=} opt_dest Destination.\n * @return {Array.} Transformed coordinates.\n */\nexport function transform2D(flatCoordinates, offset, end, stride, transform, opt_dest) {\n const dest = opt_dest ? opt_dest : [];\n let i = 0;\n for (let j = offset; j < end; j += stride) {\n const x = flatCoordinates[j];\n const y = flatCoordinates[j + 1];\n dest[i++] = transform[0] * x + transform[2] * y + transform[4];\n dest[i++] = transform[1] * x + transform[3] * y + transform[5];\n }\n if (opt_dest && dest.length != i) {\n dest.length = i;\n }\n return dest;\n}\n\n\n/**\n * @param {Array.} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {number} end End.\n * @param {number} stride Stride.\n * @param {number} angle Angle.\n * @param {Array.} anchor Rotation anchor point.\n * @param {Array.=} opt_dest Destination.\n * @return {Array.} Transformed coordinates.\n */\nexport function rotate(flatCoordinates, offset, end, stride, angle, anchor, opt_dest) {\n const dest = opt_dest ? opt_dest : [];\n const cos = Math.cos(angle);\n const sin = Math.sin(angle);\n const anchorX = anchor[0];\n const anchorY = anchor[1];\n let i = 0;\n for (let j = offset; j < end; j += stride) {\n const deltaX = flatCoordinates[j] - anchorX;\n const deltaY = flatCoordinates[j + 1] - anchorY;\n dest[i++] = anchorX + deltaX * cos - deltaY * sin;\n dest[i++] = anchorY + deltaX * sin + deltaY * cos;\n for (let k = j + 2; k < j + stride; ++k) {\n dest[i++] = flatCoordinates[k];\n }\n }\n if (opt_dest && dest.length != i) {\n dest.length = i;\n }\n return dest;\n}\n\n\n/**\n * Scale the coordinates.\n * @param {Array.} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {number} end End.\n * @param {number} stride Stride.\n * @param {number} sx Scale factor in the x-direction.\n * @param {number} sy Scale factor in the y-direction.\n * @param {Array.} anchor Scale anchor point.\n * @param {Array.=} opt_dest Destination.\n * @return {Array.} Transformed coordinates.\n */\nexport function scale(flatCoordinates, offset, end, stride, sx, sy, anchor, opt_dest) {\n const dest = opt_dest ? opt_dest : [];\n const anchorX = anchor[0];\n const anchorY = anchor[1];\n let i = 0;\n for (let j = offset; j < end; j += stride) {\n const deltaX = flatCoordinates[j] - anchorX;\n const deltaY = flatCoordinates[j + 1] - anchorY;\n dest[i++] = anchorX + sx * deltaX;\n dest[i++] = anchorY + sy * deltaY;\n for (let k = j + 2; k < j + stride; ++k) {\n dest[i++] = flatCoordinates[k];\n }\n }\n if (opt_dest && dest.length != i) {\n dest.length = i;\n }\n return dest;\n}\n\n\n/**\n * @param {Array.} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {number} end End.\n * @param {number} stride Stride.\n * @param {number} deltaX Delta X.\n * @param {number} deltaY Delta Y.\n * @param {Array.=} opt_dest Destination.\n * @return {Array.} Transformed coordinates.\n */\nexport function translate(flatCoordinates, offset, end, stride, deltaX, deltaY, opt_dest) {\n const dest = opt_dest ? opt_dest : [];\n let i = 0;\n for (let j = offset; j < end; j += stride) {\n dest[i++] = flatCoordinates[j] + deltaX;\n dest[i++] = flatCoordinates[j + 1] + deltaY;\n for (let k = j + 2; k < j + stride; ++k) {\n dest[i++] = flatCoordinates[k];\n }\n }\n if (opt_dest && dest.length != i) {\n dest.length = i;\n }\n return dest;\n}\n","/**\n * @module ol/math\n */\nimport {assert} from './asserts.js';\n\n/**\n * Takes a number and clamps it to within the provided bounds.\n * @param {number} value The input number.\n * @param {number} min The minimum value to return.\n * @param {number} max The maximum value to return.\n * @return {number} The input number if it is within bounds, or the nearest\n * number within the bounds.\n */\nexport function clamp(value, min, max) {\n return Math.min(Math.max(value, min), max);\n}\n\n\n/**\n * Return the hyperbolic cosine of a given number. The method will use the\n * native `Math.cosh` function if it is available, otherwise the hyperbolic\n * cosine will be calculated via the reference implementation of the Mozilla\n * developer network.\n *\n * @param {number} x X.\n * @return {number} Hyperbolic cosine of x.\n */\nexport const cosh = (function() {\n // Wrapped in a iife, to save the overhead of checking for the native\n // implementation on every invocation.\n let cosh;\n if ('cosh' in Math) {\n // The environment supports the native Math.cosh function, use it…\n cosh = Math.cosh;\n } else {\n // … else, use the reference implementation of MDN:\n cosh = function(x) {\n const y = Math.exp(x);\n return (y + 1 / y) / 2;\n };\n }\n return cosh;\n}());\n\n\n/**\n * @param {number} x X.\n * @return {number} The smallest power of two greater than or equal to x.\n */\nexport function roundUpToPowerOfTwo(x) {\n assert(0 < x, 29); // `x` must be greater than `0`\n return Math.pow(2, Math.ceil(Math.log(x) / Math.LN2));\n}\n\n\n/**\n * Returns the square of the closest distance between the point (x, y) and the\n * line segment (x1, y1) to (x2, y2).\n * @param {number} x X.\n * @param {number} y Y.\n * @param {number} x1 X1.\n * @param {number} y1 Y1.\n * @param {number} x2 X2.\n * @param {number} y2 Y2.\n * @return {number} Squared distance.\n */\nexport function squaredSegmentDistance(x, y, x1, y1, x2, y2) {\n const dx = x2 - x1;\n const dy = y2 - y1;\n if (dx !== 0 || dy !== 0) {\n const t = ((x - x1) * dx + (y - y1) * dy) / (dx * dx + dy * dy);\n if (t > 1) {\n x1 = x2;\n y1 = y2;\n } else if (t > 0) {\n x1 += dx * t;\n y1 += dy * t;\n }\n }\n return squaredDistance(x, y, x1, y1);\n}\n\n\n/**\n * Returns the square of the distance between the points (x1, y1) and (x2, y2).\n * @param {number} x1 X1.\n * @param {number} y1 Y1.\n * @param {number} x2 X2.\n * @param {number} y2 Y2.\n * @return {number} Squared distance.\n */\nexport function squaredDistance(x1, y1, x2, y2) {\n const dx = x2 - x1;\n const dy = y2 - y1;\n return dx * dx + dy * dy;\n}\n\n\n/**\n * Solves system of linear equations using Gaussian elimination method.\n *\n * @param {Array.>} mat Augmented matrix (n x n + 1 column)\n * in row-major order.\n * @return {Array.} The resulting vector.\n */\nexport function solveLinearSystem(mat) {\n const n = mat.length;\n\n for (let i = 0; i < n; i++) {\n // Find max in the i-th column (ignoring i - 1 first rows)\n let maxRow = i;\n let maxEl = Math.abs(mat[i][i]);\n for (let r = i + 1; r < n; r++) {\n const absValue = Math.abs(mat[r][i]);\n if (absValue > maxEl) {\n maxEl = absValue;\n maxRow = r;\n }\n }\n\n if (maxEl === 0) {\n return null; // matrix is singular\n }\n\n // Swap max row with i-th (current) row\n const tmp = mat[maxRow];\n mat[maxRow] = mat[i];\n mat[i] = tmp;\n\n // Subtract the i-th row to make all the remaining rows 0 in the i-th column\n for (let j = i + 1; j < n; j++) {\n const coef = -mat[j][i] / mat[i][i];\n for (let k = i; k < n + 1; k++) {\n if (i == k) {\n mat[j][k] = 0;\n } else {\n mat[j][k] += coef * mat[i][k];\n }\n }\n }\n }\n\n // Solve Ax=b for upper triangular matrix A (mat)\n const x = new Array(n);\n for (let l = n - 1; l >= 0; l--) {\n x[l] = mat[l][n] / mat[l][l];\n for (let m = l - 1; m >= 0; m--) {\n mat[m][n] -= mat[m][l] * x[l];\n }\n }\n return x;\n}\n\n\n/**\n * Converts radians to to degrees.\n *\n * @param {number} angleInRadians Angle in radians.\n * @return {number} Angle in degrees.\n */\nexport function toDegrees(angleInRadians) {\n return angleInRadians * 180 / Math.PI;\n}\n\n\n/**\n * Converts degrees to radians.\n *\n * @param {number} angleInDegrees Angle in degrees.\n * @return {number} Angle in radians.\n */\nexport function toRadians(angleInDegrees) {\n return angleInDegrees * Math.PI / 180;\n}\n\n/**\n * Returns the modulo of a / b, depending on the sign of b.\n *\n * @param {number} a Dividend.\n * @param {number} b Divisor.\n * @return {number} Modulo.\n */\nexport function modulo(a, b) {\n const r = a % b;\n return r * b < 0 ? r + b : r;\n}\n\n/**\n * Calculates the linearly interpolated value of x between a and b.\n *\n * @param {number} a Number\n * @param {number} b Number\n * @param {number} x Value to be interpolated.\n * @return {number} Interpolated value.\n */\nexport function lerp(a, b, x) {\n return a + x * (b - a);\n}\n","/**\n * @module ol/geom/GeometryType\n */\n\n/**\n * The geometry type. One of `'Point'`, `'LineString'`, `'LinearRing'`,\n * `'Polygon'`, `'MultiPoint'`, `'MultiLineString'`, `'MultiPolygon'`,\n * `'GeometryCollection'`, `'Circle'`.\n * @enum {string}\n */\nexport default {\n POINT: 'Point',\n LINE_STRING: 'LineString',\n LINEAR_RING: 'LinearRing',\n POLYGON: 'Polygon',\n MULTI_POINT: 'MultiPoint',\n MULTI_LINE_STRING: 'MultiLineString',\n MULTI_POLYGON: 'MultiPolygon',\n GEOMETRY_COLLECTION: 'GeometryCollection',\n CIRCLE: 'Circle'\n};\n","/**\n * @license\n * Latitude/longitude spherical geodesy formulae taken from\n * http://www.movable-type.co.uk/scripts/latlong.html\n * Licensed under CC-BY-3.0.\n */\n\n/**\n * @module ol/sphere\n */\nimport {toRadians, toDegrees} from './math.js';\nimport GeometryType from './geom/GeometryType.js';\n\n\n/**\n * Object literal with options for the {@link getLength} or {@link getArea}\n * functions.\n * @typedef {Object} SphereMetricOptions\n * @property {module:ol/proj~ProjectionLike} [projection='EPSG:3857']\n * Projection of the geometry. By default, the geometry is assumed to be in\n * Web Mercator.\n * @property {number} [radius=6371008.8] Sphere radius. By default, the radius of the\n * earth is used (Clarke 1866 Authalic Sphere).\n */\n\n\n/**\n * The mean Earth radius (1/3 * (2a + b)) for the WGS84 ellipsoid.\n * https://en.wikipedia.org/wiki/Earth_radius#Mean_radius\n * @type {number}\n */\nexport const DEFAULT_RADIUS = 6371008.8;\n\n\n/**\n * Get the great circle distance (in meters) between two geographic coordinates.\n * @param {Array} c1 Starting coordinate.\n * @param {Array} c2 Ending coordinate.\n * @param {number=} opt_radius The sphere radius to use. Defaults to the Earth's\n * mean radius using the WGS84 ellipsoid.\n * @return {number} The great circle distance between the points (in meters).\n * @api\n */\nexport function getDistance(c1, c2, opt_radius) {\n const radius = opt_radius || DEFAULT_RADIUS;\n const lat1 = toRadians(c1[1]);\n const lat2 = toRadians(c2[1]);\n const deltaLatBy2 = (lat2 - lat1) / 2;\n const deltaLonBy2 = toRadians(c2[0] - c1[0]) / 2;\n const a = Math.sin(deltaLatBy2) * Math.sin(deltaLatBy2) +\n Math.sin(deltaLonBy2) * Math.sin(deltaLonBy2) *\n Math.cos(lat1) * Math.cos(lat2);\n return 2 * radius * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));\n}\n\n\n/**\n * Get the cumulative great circle length of linestring coordinates (geographic).\n * @param {Array} coordinates Linestring coordinates.\n * @param {number} radius The sphere radius to use.\n * @return {number} The length (in meters).\n */\nfunction getLengthInternal(coordinates, radius) {\n let length = 0;\n for (let i = 0, ii = coordinates.length; i < ii - 1; ++i) {\n length += getDistance(coordinates[i], coordinates[i + 1], radius);\n }\n return length;\n}\n\n\n/**\n * Get the spherical length of a geometry. This length is the sum of the\n * great circle distances between coordinates. For polygons, the length is\n * the sum of all rings. For points, the length is zero. For multi-part\n * geometries, the length is the sum of the length of each part.\n * @param {module:ol/geom/Geometry} geometry A geometry.\n * @param {module:ol/sphere~SphereMetricOptions=} opt_options Options for the\n * length calculation. By default, geometries are assumed to be in 'EPSG:3857'.\n * You can change this by providing a `projection` option.\n * @return {number} The spherical length (in meters).\n * @api\n */\nexport function getLength(geometry, opt_options) {\n const options = opt_options || {};\n const radius = options.radius || DEFAULT_RADIUS;\n const projection = options.projection || 'EPSG:3857';\n const type = geometry.getType();\n if (type !== GeometryType.GEOMETRY_COLLECTION) {\n geometry = geometry.clone().transform(projection, 'EPSG:4326');\n }\n let length = 0;\n let coordinates, coords, i, ii, j, jj;\n switch (type) {\n case GeometryType.POINT:\n case GeometryType.MULTI_POINT: {\n break;\n }\n case GeometryType.LINE_STRING:\n case GeometryType.LINEAR_RING: {\n coordinates = /** @type {module:ol/geom/SimpleGeometry} */ (geometry).getCoordinates();\n length = getLengthInternal(coordinates, radius);\n break;\n }\n case GeometryType.MULTI_LINE_STRING:\n case GeometryType.POLYGON: {\n coordinates = /** @type {module:ol/geom/SimpleGeometry} */ (geometry).getCoordinates();\n for (i = 0, ii = coordinates.length; i < ii; ++i) {\n length += getLengthInternal(coordinates[i], radius);\n }\n break;\n }\n case GeometryType.MULTI_POLYGON: {\n coordinates = /** @type {module:ol/geom/SimpleGeometry} */ (geometry).getCoordinates();\n for (i = 0, ii = coordinates.length; i < ii; ++i) {\n coords = coordinates[i];\n for (j = 0, jj = coords.length; j < jj; ++j) {\n length += getLengthInternal(coords[j], radius);\n }\n }\n break;\n }\n case GeometryType.GEOMETRY_COLLECTION: {\n const geometries = /** @type {module:ol/geom/GeometryCollection} */ (geometry).getGeometries();\n for (i = 0, ii = geometries.length; i < ii; ++i) {\n length += getLength(geometries[i], opt_options);\n }\n break;\n }\n default: {\n throw new Error('Unsupported geometry type: ' + type);\n }\n }\n return length;\n}\n\n\n/**\n * Returns the spherical area for a list of coordinates.\n *\n * [Reference](https://trs-new.jpl.nasa.gov/handle/2014/40409)\n * Robert. G. Chamberlain and William H. Duquette, \"Some Algorithms for\n * Polygons on a Sphere\", JPL Publication 07-03, Jet Propulsion\n * Laboratory, Pasadena, CA, June 2007\n *\n * @param {Array.} coordinates List of coordinates of a linear\n * ring. If the ring is oriented clockwise, the area will be positive,\n * otherwise it will be negative.\n * @param {number} radius The sphere radius.\n * @return {number} Area (in square meters).\n */\nfunction getAreaInternal(coordinates, radius) {\n let area = 0;\n const len = coordinates.length;\n let x1 = coordinates[len - 1][0];\n let y1 = coordinates[len - 1][1];\n for (let i = 0; i < len; i++) {\n const x2 = coordinates[i][0];\n const y2 = coordinates[i][1];\n area += toRadians(x2 - x1) *\n (2 + Math.sin(toRadians(y1)) +\n Math.sin(toRadians(y2)));\n x1 = x2;\n y1 = y2;\n }\n return area * radius * radius / 2.0;\n}\n\n\n/**\n * Get the spherical area of a geometry. This is the area (in meters) assuming\n * that polygon edges are segments of great circles on a sphere.\n * @param {module:ol/geom/Geometry} geometry A geometry.\n * @param {module:ol/sphere~SphereMetricOptions=} opt_options Options for the area\n * calculation. By default, geometries are assumed to be in 'EPSG:3857'.\n * You can change this by providing a `projection` option.\n * @return {number} The spherical area (in square meters).\n * @api\n */\nexport function getArea(geometry, opt_options) {\n const options = opt_options || {};\n const radius = options.radius || DEFAULT_RADIUS;\n const projection = options.projection || 'EPSG:3857';\n const type = geometry.getType();\n if (type !== GeometryType.GEOMETRY_COLLECTION) {\n geometry = geometry.clone().transform(projection, 'EPSG:4326');\n }\n let area = 0;\n let coordinates, coords, i, ii, j, jj;\n switch (type) {\n case GeometryType.POINT:\n case GeometryType.MULTI_POINT:\n case GeometryType.LINE_STRING:\n case GeometryType.MULTI_LINE_STRING:\n case GeometryType.LINEAR_RING: {\n break;\n }\n case GeometryType.POLYGON: {\n coordinates = /** @type {module:ol/geom/Polygon} */ (geometry).getCoordinates();\n area = Math.abs(getAreaInternal(coordinates[0], radius));\n for (i = 1, ii = coordinates.length; i < ii; ++i) {\n area -= Math.abs(getAreaInternal(coordinates[i], radius));\n }\n break;\n }\n case GeometryType.MULTI_POLYGON: {\n coordinates = /** @type {module:ol/geom/SimpleGeometry} */ (geometry).getCoordinates();\n for (i = 0, ii = coordinates.length; i < ii; ++i) {\n coords = coordinates[i];\n area += Math.abs(getAreaInternal(coords[0], radius));\n for (j = 1, jj = coords.length; j < jj; ++j) {\n area -= Math.abs(getAreaInternal(coords[j], radius));\n }\n }\n break;\n }\n case GeometryType.GEOMETRY_COLLECTION: {\n const geometries = /** @type {module:ol/geom/GeometryCollection} */ (geometry).getGeometries();\n for (i = 0, ii = geometries.length; i < ii; ++i) {\n area += getArea(geometries[i], opt_options);\n }\n break;\n }\n default: {\n throw new Error('Unsupported geometry type: ' + type);\n }\n }\n return area;\n}\n\n\n/**\n * Returns the coordinate at the given distance and bearing from `c1`.\n *\n * @param {module:ol/coordinate~Coordinate} c1 The origin point (`[lon, lat]` in degrees).\n * @param {number} distance The great-circle distance between the origin\n * point and the target point.\n * @param {number} bearing The bearing (in radians).\n * @param {number=} opt_radius The sphere radius to use. Defaults to the Earth's\n * mean radius using the WGS84 ellipsoid.\n * @return {module:ol/coordinate~Coordinate} The target point.\n */\nexport function offset(c1, distance, bearing, opt_radius) {\n const radius = opt_radius || DEFAULT_RADIUS;\n const lat1 = toRadians(c1[1]);\n const lon1 = toRadians(c1[0]);\n const dByR = distance / radius;\n const lat = Math.asin(\n Math.sin(lat1) * Math.cos(dByR) +\n Math.cos(lat1) * Math.sin(dByR) * Math.cos(bearing));\n const lon = lon1 + Math.atan2(\n Math.sin(bearing) * Math.sin(dByR) * Math.cos(lat1),\n Math.cos(dByR) - Math.sin(lat1) * Math.sin(lat));\n return [toDegrees(lon), toDegrees(lat)];\n}\n","/**\n * @module ol/proj/Units\n */\n\n/**\n * Projection units: `'degrees'`, `'ft'`, `'m'`, `'pixels'`, `'tile-pixels'` or\n * `'us-ft'`.\n * @enum {string}\n */\nconst Units = {\n DEGREES: 'degrees',\n FEET: 'ft',\n METERS: 'm',\n PIXELS: 'pixels',\n TILE_PIXELS: 'tile-pixels',\n USFEET: 'us-ft'\n};\n\n\n/**\n * Meters per unit lookup table.\n * @const\n * @type {Object.}\n * @api\n */\nexport const METERS_PER_UNIT = {};\n// use the radius of the Normal sphere\nMETERS_PER_UNIT[Units.DEGREES] = 2 * Math.PI * 6370997 / 360;\nMETERS_PER_UNIT[Units.FEET] = 0.3048;\nMETERS_PER_UNIT[Units.METERS] = 1;\nMETERS_PER_UNIT[Units.USFEET] = 1200 / 3937;\n\nexport default Units;\n","/**\n * @module ol/proj/Projection\n */\nimport {METERS_PER_UNIT} from '../proj/Units.js';\n\n\n/**\n * @typedef {Object} Options\n * @property {string} code The SRS identifier code, e.g. `EPSG:4326`.\n * @property {module:ol/proj/Units|string} [units] Units. Required unless a\n * proj4 projection is defined for `code`.\n * @property {module:ol/extent~Extent} [extent] The validity extent for the SRS.\n * @property {string} [axisOrientation='enu'] The axis orientation as specified in Proj4.\n * @property {boolean} [global=false] Whether the projection is valid for the whole globe.\n * @property {number} [metersPerUnit] The meters per unit for the SRS.\n * If not provided, the `units` are used to get the meters per unit from the {@link module:ol/proj/Units~METERS_PER_UNIT}\n * lookup table.\n * @property {module:ol/extent~Extent} [worldExtent] The world extent for the SRS.\n * @property {function(number, module:ol/coordinate~Coordinate):number} [getPointResolution]\n * Function to determine resolution at a point. The function is called with a\n * `{number}` view resolution and an `{module:ol/coordinate~Coordinate}` as arguments, and returns\n * the `{number}` resolution at the passed coordinate. If this is `undefined`,\n * the default {@link module:ol/proj#getPointResolution} function will be used.\n */\n\n\n/**\n * @classdesc\n * Projection definition class. One of these is created for each projection\n * supported in the application and stored in the {@link module:ol/proj} namespace.\n * You can use these in applications, but this is not required, as API params\n * and options use {@link module:ol/proj~ProjectionLike} which means the simple string\n * code will suffice.\n *\n * You can use {@link module:ol/proj~get} to retrieve the object for a particular\n * projection.\n *\n * The library includes definitions for `EPSG:4326` and `EPSG:3857`, together\n * with the following aliases:\n * * `EPSG:4326`: CRS:84, urn:ogc:def:crs:EPSG:6.6:4326,\n * urn:ogc:def:crs:OGC:1.3:CRS84, urn:ogc:def:crs:OGC:2:84,\n * http://www.opengis.net/gml/srs/epsg.xml#4326,\n * urn:x-ogc:def:crs:EPSG:4326\n * * `EPSG:3857`: EPSG:102100, EPSG:102113, EPSG:900913,\n * urn:ogc:def:crs:EPSG:6.18:3:3857,\n * http://www.opengis.net/gml/srs/epsg.xml#3857\n *\n * If you use proj4js, aliases can be added using `proj4.defs()`; see\n * [documentation](https://github.com/proj4js/proj4js). To set an alternative\n * namespace for proj4, use {@link module:ol/proj~setProj4}.\n *\n * @constructor\n * @param {module:ol/proj/Projection~Options} options Projection options.\n * @struct\n * @api\n */\nconst Projection = function(options) {\n /**\n * @private\n * @type {string}\n */\n this.code_ = options.code;\n\n /**\n * Units of projected coordinates. When set to `TILE_PIXELS`, a\n * `this.extent_` and `this.worldExtent_` must be configured properly for each\n * tile.\n * @private\n * @type {module:ol/proj/Units}\n */\n this.units_ = /** @type {module:ol/proj/Units} */ (options.units);\n\n /**\n * Validity extent of the projection in projected coordinates. For projections\n * with `TILE_PIXELS` units, this is the extent of the tile in\n * tile pixel space.\n * @private\n * @type {module:ol/extent~Extent}\n */\n this.extent_ = options.extent !== undefined ? options.extent : null;\n\n /**\n * Extent of the world in EPSG:4326. For projections with\n * `TILE_PIXELS` units, this is the extent of the tile in\n * projected coordinate space.\n * @private\n * @type {module:ol/extent~Extent}\n */\n this.worldExtent_ = options.worldExtent !== undefined ?\n options.worldExtent : null;\n\n /**\n * @private\n * @type {string}\n */\n this.axisOrientation_ = options.axisOrientation !== undefined ?\n options.axisOrientation : 'enu';\n\n /**\n * @private\n * @type {boolean}\n */\n this.global_ = options.global !== undefined ? options.global : false;\n\n /**\n * @private\n * @type {boolean}\n */\n this.canWrapX_ = !!(this.global_ && this.extent_);\n\n /**\n * @private\n * @type {function(number, module:ol/coordinate~Coordinate):number|undefined}\n */\n this.getPointResolutionFunc_ = options.getPointResolution;\n\n /**\n * @private\n * @type {module:ol/tilegrid/TileGrid}\n */\n this.defaultTileGrid_ = null;\n\n /**\n * @private\n * @type {number|undefined}\n */\n this.metersPerUnit_ = options.metersPerUnit;\n};\n\n\n/**\n * @return {boolean} The projection is suitable for wrapping the x-axis\n */\nProjection.prototype.canWrapX = function() {\n return this.canWrapX_;\n};\n\n\n/**\n * Get the code for this projection, e.g. 'EPSG:4326'.\n * @return {string} Code.\n * @api\n */\nProjection.prototype.getCode = function() {\n return this.code_;\n};\n\n\n/**\n * Get the validity extent for this projection.\n * @return {module:ol/extent~Extent} Extent.\n * @api\n */\nProjection.prototype.getExtent = function() {\n return this.extent_;\n};\n\n\n/**\n * Get the units of this projection.\n * @return {module:ol/proj/Units} Units.\n * @api\n */\nProjection.prototype.getUnits = function() {\n return this.units_;\n};\n\n\n/**\n * Get the amount of meters per unit of this projection. If the projection is\n * not configured with `metersPerUnit` or a units identifier, the return is\n * `undefined`.\n * @return {number|undefined} Meters.\n * @api\n */\nProjection.prototype.getMetersPerUnit = function() {\n return this.metersPerUnit_ || METERS_PER_UNIT[this.units_];\n};\n\n\n/**\n * Get the world extent for this projection.\n * @return {module:ol/extent~Extent} Extent.\n * @api\n */\nProjection.prototype.getWorldExtent = function() {\n return this.worldExtent_;\n};\n\n\n/**\n * Get the axis orientation of this projection.\n * Example values are:\n * enu - the default easting, northing, elevation.\n * neu - northing, easting, up - useful for \"lat/long\" geographic coordinates,\n * or south orientated transverse mercator.\n * wnu - westing, northing, up - some planetary coordinate systems have\n * \"west positive\" coordinate systems\n * @return {string} Axis orientation.\n * @api\n */\nProjection.prototype.getAxisOrientation = function() {\n return this.axisOrientation_;\n};\n\n\n/**\n * Is this projection a global projection which spans the whole world?\n * @return {boolean} Whether the projection is global.\n * @api\n */\nProjection.prototype.isGlobal = function() {\n return this.global_;\n};\n\n\n/**\n* Set if the projection is a global projection which spans the whole world\n* @param {boolean} global Whether the projection is global.\n* @api\n*/\nProjection.prototype.setGlobal = function(global) {\n this.global_ = global;\n this.canWrapX_ = !!(global && this.extent_);\n};\n\n\n/**\n * @return {module:ol/tilegrid/TileGrid} The default tile grid.\n */\nProjection.prototype.getDefaultTileGrid = function() {\n return this.defaultTileGrid_;\n};\n\n\n/**\n * @param {module:ol/tilegrid/TileGrid} tileGrid The default tile grid.\n */\nProjection.prototype.setDefaultTileGrid = function(tileGrid) {\n this.defaultTileGrid_ = tileGrid;\n};\n\n\n/**\n * Set the validity extent for this projection.\n * @param {module:ol/extent~Extent} extent Extent.\n * @api\n */\nProjection.prototype.setExtent = function(extent) {\n this.extent_ = extent;\n this.canWrapX_ = !!(this.global_ && extent);\n};\n\n\n/**\n * Set the world extent for this projection.\n * @param {module:ol/extent~Extent} worldExtent World extent\n * [minlon, minlat, maxlon, maxlat].\n * @api\n */\nProjection.prototype.setWorldExtent = function(worldExtent) {\n this.worldExtent_ = worldExtent;\n};\n\n\n/**\n * Set the getPointResolution function (see {@link module:ol/proj~getPointResolution}\n * for this projection.\n * @param {function(number, module:ol/coordinate~Coordinate):number} func Function\n * @api\n */\nProjection.prototype.setGetPointResolution = function(func) {\n this.getPointResolutionFunc_ = func;\n};\n\n\n/**\n * Get the custom point resolution function for this projection (if set).\n * @return {function(number, module:ol/coordinate~Coordinate):number|undefined} The custom point\n * resolution function (if set).\n */\nProjection.prototype.getPointResolutionFunc = function() {\n return this.getPointResolutionFunc_;\n};\nexport default Projection;\n","/**\n * @module ol/proj/epsg3857\n */\nimport {inherits} from '../util.js';\nimport {cosh} from '../math.js';\nimport Projection from '../proj/Projection.js';\nimport Units from '../proj/Units.js';\n\n\n/**\n * Radius of WGS84 sphere\n *\n * @const\n * @type {number}\n */\nexport const RADIUS = 6378137;\n\n\n/**\n * @const\n * @type {number}\n */\nexport const HALF_SIZE = Math.PI * RADIUS;\n\n\n/**\n * @const\n * @type {module:ol/extent~Extent}\n */\nexport const EXTENT = [\n -HALF_SIZE, -HALF_SIZE,\n HALF_SIZE, HALF_SIZE\n];\n\n\n/**\n * @const\n * @type {module:ol/extent~Extent}\n */\nexport const WORLD_EXTENT = [-180, -85, 180, 85];\n\n\n/**\n * @classdesc\n * Projection object for web/spherical Mercator (EPSG:3857).\n *\n * @constructor\n * @extends {module:ol/proj/Projection}\n * @param {string} code Code.\n */\nfunction EPSG3857Projection(code) {\n Projection.call(this, {\n code: code,\n units: Units.METERS,\n extent: EXTENT,\n global: true,\n worldExtent: WORLD_EXTENT,\n getPointResolution: function(resolution, point) {\n return resolution / cosh(point[1] / RADIUS);\n }\n });\n}\ninherits(EPSG3857Projection, Projection);\n\n\n/**\n * Projections equal to EPSG:3857.\n *\n * @const\n * @type {Array.}\n */\nexport const PROJECTIONS = [\n new EPSG3857Projection('EPSG:3857'),\n new EPSG3857Projection('EPSG:102100'),\n new EPSG3857Projection('EPSG:102113'),\n new EPSG3857Projection('EPSG:900913'),\n new EPSG3857Projection('urn:ogc:def:crs:EPSG:6.18:3:3857'),\n new EPSG3857Projection('urn:ogc:def:crs:EPSG::3857'),\n new EPSG3857Projection('http://www.opengis.net/gml/srs/epsg.xml#3857')\n];\n\n\n/**\n * Transformation from EPSG:4326 to EPSG:3857.\n *\n * @param {Array.} input Input array of coordinate values.\n * @param {Array.=} opt_output Output array of coordinate values.\n * @param {number=} opt_dimension Dimension (default is `2`).\n * @return {Array.} Output array of coordinate values.\n */\nexport function fromEPSG4326(input, opt_output, opt_dimension) {\n const length = input.length;\n const dimension = opt_dimension > 1 ? opt_dimension : 2;\n let output = opt_output;\n if (output === undefined) {\n if (dimension > 2) {\n // preserve values beyond second dimension\n output = input.slice();\n } else {\n output = new Array(length);\n }\n }\n const halfSize = HALF_SIZE;\n for (let i = 0; i < length; i += dimension) {\n output[i] = halfSize * input[i] / 180;\n let y = RADIUS *\n Math.log(Math.tan(Math.PI * (input[i + 1] + 90) / 360));\n if (y > halfSize) {\n y = halfSize;\n } else if (y < -halfSize) {\n y = -halfSize;\n }\n output[i + 1] = y;\n }\n return output;\n}\n\n\n/**\n * Transformation from EPSG:3857 to EPSG:4326.\n *\n * @param {Array.} input Input array of coordinate values.\n * @param {Array.=} opt_output Output array of coordinate values.\n * @param {number=} opt_dimension Dimension (default is `2`).\n * @return {Array.} Output array of coordinate values.\n */\nexport function toEPSG4326(input, opt_output, opt_dimension) {\n const length = input.length;\n const dimension = opt_dimension > 1 ? opt_dimension : 2;\n let output = opt_output;\n if (output === undefined) {\n if (dimension > 2) {\n // preserve values beyond second dimension\n output = input.slice();\n } else {\n output = new Array(length);\n }\n }\n for (let i = 0; i < length; i += dimension) {\n output[i] = 180 * input[i] / HALF_SIZE;\n output[i + 1] = 360 * Math.atan(\n Math.exp(input[i + 1] / RADIUS)) / Math.PI - 90;\n }\n return output;\n}\n","/**\n * @module ol/proj/epsg4326\n */\nimport {inherits} from '../util.js';\nimport Projection from '../proj/Projection.js';\nimport Units from '../proj/Units.js';\n\n\n/**\n * Semi-major radius of the WGS84 ellipsoid.\n *\n * @const\n * @type {number}\n */\nexport const RADIUS = 6378137;\n\n\n/**\n * Extent of the EPSG:4326 projection which is the whole world.\n *\n * @const\n * @type {module:ol/extent~Extent}\n */\nexport const EXTENT = [-180, -90, 180, 90];\n\n\n/**\n * @const\n * @type {number}\n */\nexport const METERS_PER_UNIT = Math.PI * RADIUS / 180;\n\n\n/**\n * @classdesc\n * Projection object for WGS84 geographic coordinates (EPSG:4326).\n *\n * Note that OpenLayers does not strictly comply with the EPSG definition.\n * The EPSG registry defines 4326 as a CRS for Latitude,Longitude (y,x).\n * OpenLayers treats EPSG:4326 as a pseudo-projection, with x,y coordinates.\n *\n * @constructor\n * @extends {module:ol/proj/Projection}\n * @param {string} code Code.\n * @param {string=} opt_axisOrientation Axis orientation.\n */\nfunction EPSG4326Projection(code, opt_axisOrientation) {\n Projection.call(this, {\n code: code,\n units: Units.DEGREES,\n extent: EXTENT,\n axisOrientation: opt_axisOrientation,\n global: true,\n metersPerUnit: METERS_PER_UNIT,\n worldExtent: EXTENT\n });\n}\ninherits(EPSG4326Projection, Projection);\n\n\n/**\n * Projections equal to EPSG:4326.\n *\n * @const\n * @type {Array.}\n */\nexport const PROJECTIONS = [\n new EPSG4326Projection('CRS:84'),\n new EPSG4326Projection('EPSG:4326', 'neu'),\n new EPSG4326Projection('urn:ogc:def:crs:EPSG::4326', 'neu'),\n new EPSG4326Projection('urn:ogc:def:crs:EPSG:6.6:4326', 'neu'),\n new EPSG4326Projection('urn:ogc:def:crs:OGC:1.3:CRS84'),\n new EPSG4326Projection('urn:ogc:def:crs:OGC:2:84'),\n new EPSG4326Projection('http://www.opengis.net/gml/srs/epsg.xml#4326', 'neu'),\n new EPSG4326Projection('urn:x-ogc:def:crs:EPSG:4326', 'neu')\n];\n","/**\n * @module ol/proj/projections\n */\n\n\n/**\n * @type {Object.}\n */\nlet cache = {};\n\n\n/**\n * Clear the projections cache.\n */\nexport function clear() {\n cache = {};\n}\n\n\n/**\n * Get a cached projection by code.\n * @param {string} code The code for the projection.\n * @return {module:ol/proj/Projection} The projection (if cached).\n */\nexport function get(code) {\n return cache[code] || null;\n}\n\n\n/**\n * Add a projection to the cache.\n * @param {string} code The projection code.\n * @param {module:ol/proj/Projection} projection The projection to cache.\n */\nexport function add(code, projection) {\n cache[code] = projection;\n}\n","/**\n * @module ol/proj/transforms\n */\nimport {isEmpty} from '../obj.js';\n\n\n/**\n * @private\n * @type {!Object.>}\n */\nlet transforms = {};\n\n\n/**\n * Clear the transform cache.\n */\nexport function clear() {\n transforms = {};\n}\n\n\n/**\n * Registers a conversion function to convert coordinates from the source\n * projection to the destination projection.\n *\n * @param {module:ol/proj/Projection} source Source.\n * @param {module:ol/proj/Projection} destination Destination.\n * @param {module:ol/proj~TransformFunction} transformFn Transform.\n */\nexport function add(source, destination, transformFn) {\n const sourceCode = source.getCode();\n const destinationCode = destination.getCode();\n if (!(sourceCode in transforms)) {\n transforms[sourceCode] = {};\n }\n transforms[sourceCode][destinationCode] = transformFn;\n}\n\n\n/**\n * Unregisters the conversion function to convert coordinates from the source\n * projection to the destination projection. This method is used to clean up\n * cached transforms during testing.\n *\n * @param {module:ol/proj/Projection} source Source projection.\n * @param {module:ol/proj/Projection} destination Destination projection.\n * @return {module:ol/proj~TransformFunction} transformFn The unregistered transform.\n */\nexport function remove(source, destination) {\n const sourceCode = source.getCode();\n const destinationCode = destination.getCode();\n const transform = transforms[sourceCode][destinationCode];\n delete transforms[sourceCode][destinationCode];\n if (isEmpty(transforms[sourceCode])) {\n delete transforms[sourceCode];\n }\n return transform;\n}\n\n\n/**\n * Get a transform given a source code and a destination code.\n * @param {string} sourceCode The code for the source projection.\n * @param {string} destinationCode The code for the destination projection.\n * @return {module:ol/proj~TransformFunction|undefined} The transform function (if found).\n */\nexport function get(sourceCode, destinationCode) {\n let transform;\n if (sourceCode in transforms && destinationCode in transforms[sourceCode]) {\n transform = transforms[sourceCode][destinationCode];\n }\n return transform;\n}\n","/**\n * @module ol/proj\n */\n\n/**\n * The ol/proj module stores:\n * * a list of {@link module:ol/proj/Projection}\n * objects, one for each projection supported by the application\n * * a list of transform functions needed to convert coordinates in one projection\n * into another.\n *\n * The static functions are the methods used to maintain these.\n * Each transform function can handle not only simple coordinate pairs, but also\n * large arrays of coordinates such as vector geometries.\n *\n * When loaded, the library adds projection objects for EPSG:4326 (WGS84\n * geographic coordinates) and EPSG:3857 (Web or Spherical Mercator, as used\n * for example by Bing Maps or OpenStreetMap), together with the relevant\n * transform functions.\n *\n * Additional transforms may be added by using the {@link http://proj4js.org/}\n * library (version 2.2 or later). You can use the full build supplied by\n * Proj4js, or create a custom build to support those projections you need; see\n * the Proj4js website for how to do this. You also need the Proj4js definitions\n * for the required projections. These definitions can be obtained from\n * {@link https://epsg.io/}, and are a JS function, so can be loaded in a script\n * tag (as in the examples) or pasted into your application.\n *\n * After all required projection definitions are added to proj4's registry (by\n * using `proj4.defs()`), simply call `register(proj4)` from the `ol/proj/proj4`\n * package. Existing transforms are not changed by this function. See\n * examples/wms-image-custom-proj for an example of this.\n *\n * Additional projection definitions can be registered with `proj4.defs()` any\n * time. Just make sure to call `register(proj4)` again; for example, with user-supplied data where you don't\n * know in advance what projections are needed, you can initially load minimal\n * support and then load whichever are requested.\n *\n * Note that Proj4js does not support projection extents. If you want to add\n * one for creating default tile grids, you can add it after the Projection\n * object has been created with `setExtent`, for example,\n * `get('EPSG:1234').setExtent(extent)`.\n *\n * In addition to Proj4js support, any transform functions can be added with\n * {@link module:ol/proj~addCoordinateTransforms}. To use this, you must first create\n * a {@link module:ol/proj/Projection} object for the new projection and add it with\n * {@link module:ol/proj~addProjection}. You can then add the forward and inverse\n * functions with {@link module:ol/proj~addCoordinateTransforms}. See\n * examples/wms-custom-proj for an example of this.\n *\n * Note that if no transforms are needed and you only need to define the\n * projection, just add a {@link module:ol/proj/Projection} with\n * {@link module:ol/proj~addProjection}. See examples/wms-no-proj for an example of\n * this.\n */\nimport {getDistance} from './sphere.js';\nimport {applyTransform} from './extent.js';\nimport {modulo} from './math.js';\nimport {toEPSG4326, fromEPSG4326, PROJECTIONS as EPSG3857_PROJECTIONS} from './proj/epsg3857.js';\nimport {PROJECTIONS as EPSG4326_PROJECTIONS} from './proj/epsg4326.js';\nimport Projection from './proj/Projection.js';\nimport Units, {METERS_PER_UNIT} from './proj/Units.js';\nimport * as projections from './proj/projections.js';\nimport {add as addTransformFunc, clear as clearTransformFuncs, get as getTransformFunc} from './proj/transforms.js';\n\n\n/**\n * A projection as {@link module:ol/proj/Projection}, SRS identifier\n * string or undefined.\n * @typedef {module:ol/proj/Projection|string|undefined} ProjectionLike\n * @api\n */\n\n\n/**\n * A transform function accepts an array of input coordinate values, an optional\n * output array, and an optional dimension (default should be 2). The function\n * transforms the input coordinate values, populates the output array, and\n * returns the output array.\n *\n * @typedef {function(Array., Array.=, number=): Array.} TransformFunction\n * @api\n */\n\n\nexport {METERS_PER_UNIT};\n\n\n/**\n * @param {Array.} input Input coordinate array.\n * @param {Array.=} opt_output Output array of coordinate values.\n * @param {number=} opt_dimension Dimension.\n * @return {Array.} Output coordinate array (new array, same coordinate\n * values).\n */\nexport function cloneTransform(input, opt_output, opt_dimension) {\n let output;\n if (opt_output !== undefined) {\n for (let i = 0, ii = input.length; i < ii; ++i) {\n opt_output[i] = input[i];\n }\n output = opt_output;\n } else {\n output = input.slice();\n }\n return output;\n}\n\n\n/**\n * @param {Array.} input Input coordinate array.\n * @param {Array.=} opt_output Output array of coordinate values.\n * @param {number=} opt_dimension Dimension.\n * @return {Array.} Input coordinate array (same array as input).\n */\nexport function identityTransform(input, opt_output, opt_dimension) {\n if (opt_output !== undefined && input !== opt_output) {\n for (let i = 0, ii = input.length; i < ii; ++i) {\n opt_output[i] = input[i];\n }\n input = opt_output;\n }\n return input;\n}\n\n\n/**\n * Add a Projection object to the list of supported projections that can be\n * looked up by their code.\n *\n * @param {module:ol/proj/Projection} projection Projection instance.\n * @api\n */\nexport function addProjection(projection) {\n projections.add(projection.getCode(), projection);\n addTransformFunc(projection, projection, cloneTransform);\n}\n\n\n/**\n * @param {Array.} projections Projections.\n */\nexport function addProjections(projections) {\n projections.forEach(addProjection);\n}\n\n\n/**\n * Fetches a Projection object for the code specified.\n *\n * @param {module:ol/proj~ProjectionLike} projectionLike Either a code string which is\n * a combination of authority and identifier such as \"EPSG:4326\", or an\n * existing projection object, or undefined.\n * @return {module:ol/proj/Projection} Projection object, or null if not in list.\n * @api\n */\nexport function get(projectionLike) {\n let projection = null;\n if (projectionLike instanceof Projection) {\n projection = projectionLike;\n } else if (typeof projectionLike === 'string') {\n const code = projectionLike;\n projection = projections.get(code);\n }\n return projection;\n}\n\n\n/**\n * Get the resolution of the point in degrees or distance units.\n * For projections with degrees as the unit this will simply return the\n * provided resolution. For other projections the point resolution is\n * by default estimated by transforming the 'point' pixel to EPSG:4326,\n * measuring its width and height on the normal sphere,\n * and taking the average of the width and height.\n * A custom function can be provided for a specific projection, either\n * by setting the `getPointResolution` option in the\n * {@link module:ol/proj/Projection~Projection} constructor or by using\n * {@link module:ol/proj/Projection~Projection#setGetPointResolution} to change an existing\n * projection object.\n * @param {module:ol/proj~ProjectionLike} projection The projection.\n * @param {number} resolution Nominal resolution in projection units.\n * @param {module:ol/coordinate~Coordinate} point Point to find adjusted resolution at.\n * @param {module:ol/proj/Units=} opt_units Units to get the point resolution in.\n * Default is the projection's units.\n * @return {number} Point resolution.\n * @api\n */\nexport function getPointResolution(projection, resolution, point, opt_units) {\n projection = get(projection);\n let pointResolution;\n const getter = projection.getPointResolutionFunc();\n if (getter) {\n pointResolution = getter(resolution, point);\n } else {\n const units = projection.getUnits();\n if (units == Units.DEGREES && !opt_units || opt_units == Units.DEGREES) {\n pointResolution = resolution;\n } else {\n // Estimate point resolution by transforming the center pixel to EPSG:4326,\n // measuring its width and height on the normal sphere, and taking the\n // average of the width and height.\n const toEPSG4326 = getTransformFromProjections(projection, get('EPSG:4326'));\n let vertices = [\n point[0] - resolution / 2, point[1],\n point[0] + resolution / 2, point[1],\n point[0], point[1] - resolution / 2,\n point[0], point[1] + resolution / 2\n ];\n vertices = toEPSG4326(vertices, vertices, 2);\n const width = getDistance(vertices.slice(0, 2), vertices.slice(2, 4));\n const height = getDistance(vertices.slice(4, 6), vertices.slice(6, 8));\n pointResolution = (width + height) / 2;\n const metersPerUnit = opt_units ?\n METERS_PER_UNIT[opt_units] :\n projection.getMetersPerUnit();\n if (metersPerUnit !== undefined) {\n pointResolution /= metersPerUnit;\n }\n }\n }\n return pointResolution;\n}\n\n\n/**\n * Registers transformation functions that don't alter coordinates. Those allow\n * to transform between projections with equal meaning.\n *\n * @param {Array.} projections Projections.\n * @api\n */\nexport function addEquivalentProjections(projections) {\n addProjections(projections);\n projections.forEach(function(source) {\n projections.forEach(function(destination) {\n if (source !== destination) {\n addTransformFunc(source, destination, cloneTransform);\n }\n });\n });\n}\n\n\n/**\n * Registers transformation functions to convert coordinates in any projection\n * in projection1 to any projection in projection2.\n *\n * @param {Array.} projections1 Projections with equal\n * meaning.\n * @param {Array.} projections2 Projections with equal\n * meaning.\n * @param {module:ol/proj~TransformFunction} forwardTransform Transformation from any\n * projection in projection1 to any projection in projection2.\n * @param {module:ol/proj~TransformFunction} inverseTransform Transform from any projection\n * in projection2 to any projection in projection1..\n */\nexport function addEquivalentTransforms(projections1, projections2, forwardTransform, inverseTransform) {\n projections1.forEach(function(projection1) {\n projections2.forEach(function(projection2) {\n addTransformFunc(projection1, projection2, forwardTransform);\n addTransformFunc(projection2, projection1, inverseTransform);\n });\n });\n}\n\n\n/**\n * Clear all cached projections and transforms.\n */\nexport function clearAllProjections() {\n projections.clear();\n clearTransformFuncs();\n}\n\n\n/**\n * @param {module:ol/proj/Projection|string|undefined} projection Projection.\n * @param {string} defaultCode Default code.\n * @return {module:ol/proj/Projection} Projection.\n */\nexport function createProjection(projection, defaultCode) {\n if (!projection) {\n return get(defaultCode);\n } else if (typeof projection === 'string') {\n return get(projection);\n } else {\n return (\n /** @type {module:ol/proj/Projection} */ (projection)\n );\n }\n}\n\n\n/**\n * Creates a {@link module:ol/proj~TransformFunction} from a simple 2D coordinate transform\n * function.\n * @param {function(module:ol/coordinate~Coordinate): module:ol/coordinate~Coordinate} coordTransform Coordinate\n * transform.\n * @return {module:ol/proj~TransformFunction} Transform function.\n */\nexport function createTransformFromCoordinateTransform(coordTransform) {\n return (\n /**\n * @param {Array.} input Input.\n * @param {Array.=} opt_output Output.\n * @param {number=} opt_dimension Dimension.\n * @return {Array.} Output.\n */\n function(input, opt_output, opt_dimension) {\n const length = input.length;\n const dimension = opt_dimension !== undefined ? opt_dimension : 2;\n const output = opt_output !== undefined ? opt_output : new Array(length);\n for (let i = 0; i < length; i += dimension) {\n const point = coordTransform([input[i], input[i + 1]]);\n output[i] = point[0];\n output[i + 1] = point[1];\n for (let j = dimension - 1; j >= 2; --j) {\n output[i + j] = input[i + j];\n }\n }\n return output;\n });\n}\n\n\n/**\n * Registers coordinate transform functions to convert coordinates between the\n * source projection and the destination projection.\n * The forward and inverse functions convert coordinate pairs; this function\n * converts these into the functions used internally which also handle\n * extents and coordinate arrays.\n *\n * @param {module:ol/proj~ProjectionLike} source Source projection.\n * @param {module:ol/proj~ProjectionLike} destination Destination projection.\n * @param {function(module:ol/coordinate~Coordinate): module:ol/coordinate~Coordinate} forward The forward transform\n * function (that is, from the source projection to the destination\n * projection) that takes a {@link module:ol/coordinate~Coordinate} as argument and returns\n * the transformed {@link module:ol/coordinate~Coordinate}.\n * @param {function(module:ol/coordinate~Coordinate): module:ol/coordinate~Coordinate} inverse The inverse transform\n * function (that is, from the destination projection to the source\n * projection) that takes a {@link module:ol/coordinate~Coordinate} as argument and returns\n * the transformed {@link module:ol/coordinate~Coordinate}.\n * @api\n */\nexport function addCoordinateTransforms(source, destination, forward, inverse) {\n const sourceProj = get(source);\n const destProj = get(destination);\n addTransformFunc(sourceProj, destProj, createTransformFromCoordinateTransform(forward));\n addTransformFunc(destProj, sourceProj, createTransformFromCoordinateTransform(inverse));\n}\n\n\n/**\n * Transforms a coordinate from longitude/latitude to a different projection.\n * @param {module:ol/coordinate~Coordinate} coordinate Coordinate as longitude and latitude, i.e.\n * an array with longitude as 1st and latitude as 2nd element.\n * @param {module:ol/proj~ProjectionLike=} opt_projection Target projection. The\n * default is Web Mercator, i.e. 'EPSG:3857'.\n * @return {module:ol/coordinate~Coordinate} Coordinate projected to the target projection.\n * @api\n */\nexport function fromLonLat(coordinate, opt_projection) {\n return transform(coordinate, 'EPSG:4326',\n opt_projection !== undefined ? opt_projection : 'EPSG:3857');\n}\n\n\n/**\n * Transforms a coordinate to longitude/latitude.\n * @param {module:ol/coordinate~Coordinate} coordinate Projected coordinate.\n * @param {module:ol/proj~ProjectionLike=} opt_projection Projection of the coordinate.\n * The default is Web Mercator, i.e. 'EPSG:3857'.\n * @return {module:ol/coordinate~Coordinate} Coordinate as longitude and latitude, i.e. an array\n * with longitude as 1st and latitude as 2nd element.\n * @api\n */\nexport function toLonLat(coordinate, opt_projection) {\n const lonLat = transform(coordinate,\n opt_projection !== undefined ? opt_projection : 'EPSG:3857', 'EPSG:4326');\n const lon = lonLat[0];\n if (lon < -180 || lon > 180) {\n lonLat[0] = modulo(lon + 180, 360) - 180;\n }\n return lonLat;\n}\n\n\n/**\n * Checks if two projections are the same, that is every coordinate in one\n * projection does represent the same geographic point as the same coordinate in\n * the other projection.\n *\n * @param {module:ol/proj/Projection} projection1 Projection 1.\n * @param {module:ol/proj/Projection} projection2 Projection 2.\n * @return {boolean} Equivalent.\n * @api\n */\nexport function equivalent(projection1, projection2) {\n if (projection1 === projection2) {\n return true;\n }\n const equalUnits = projection1.getUnits() === projection2.getUnits();\n if (projection1.getCode() === projection2.getCode()) {\n return equalUnits;\n } else {\n const transformFunc = getTransformFromProjections(projection1, projection2);\n return transformFunc === cloneTransform && equalUnits;\n }\n}\n\n\n/**\n * Searches in the list of transform functions for the function for converting\n * coordinates from the source projection to the destination projection.\n *\n * @param {module:ol/proj/Projection} sourceProjection Source Projection object.\n * @param {module:ol/proj/Projection} destinationProjection Destination Projection\n * object.\n * @return {module:ol/proj~TransformFunction} Transform function.\n */\nexport function getTransformFromProjections(sourceProjection, destinationProjection) {\n const sourceCode = sourceProjection.getCode();\n const destinationCode = destinationProjection.getCode();\n let transformFunc = getTransformFunc(sourceCode, destinationCode);\n if (!transformFunc) {\n transformFunc = identityTransform;\n }\n return transformFunc;\n}\n\n\n/**\n * Given the projection-like objects, searches for a transformation\n * function to convert a coordinates array from the source projection to the\n * destination projection.\n *\n * @param {module:ol/proj~ProjectionLike} source Source.\n * @param {module:ol/proj~ProjectionLike} destination Destination.\n * @return {module:ol/proj~TransformFunction} Transform function.\n * @api\n */\nexport function getTransform(source, destination) {\n const sourceProjection = get(source);\n const destinationProjection = get(destination);\n return getTransformFromProjections(sourceProjection, destinationProjection);\n}\n\n\n/**\n * Transforms a coordinate from source projection to destination projection.\n * This returns a new coordinate (and does not modify the original).\n *\n * See {@link module:ol/proj~transformExtent} for extent transformation.\n * See the transform method of {@link module:ol/geom/Geometry~Geometry} and its\n * subclasses for geometry transforms.\n *\n * @param {module:ol/coordinate~Coordinate} coordinate Coordinate.\n * @param {module:ol/proj~ProjectionLike} source Source projection-like.\n * @param {module:ol/proj~ProjectionLike} destination Destination projection-like.\n * @return {module:ol/coordinate~Coordinate} Coordinate.\n * @api\n */\nexport function transform(coordinate, source, destination) {\n const transformFunc = getTransform(source, destination);\n return transformFunc(coordinate, undefined, coordinate.length);\n}\n\n\n/**\n * Transforms an extent from source projection to destination projection. This\n * returns a new extent (and does not modify the original).\n *\n * @param {module:ol/extent~Extent} extent The extent to transform.\n * @param {module:ol/proj~ProjectionLike} source Source projection-like.\n * @param {module:ol/proj~ProjectionLike} destination Destination projection-like.\n * @return {module:ol/extent~Extent} The transformed extent.\n * @api\n */\nexport function transformExtent(extent, source, destination) {\n const transformFunc = getTransform(source, destination);\n return applyTransform(extent, transformFunc);\n}\n\n\n/**\n * Transforms the given point to the destination projection.\n *\n * @param {module:ol/coordinate~Coordinate} point Point.\n * @param {module:ol/proj/Projection} sourceProjection Source projection.\n * @param {module:ol/proj/Projection} destinationProjection Destination projection.\n * @return {module:ol/coordinate~Coordinate} Point.\n */\nexport function transformWithProjections(point, sourceProjection, destinationProjection) {\n const transformFunc = getTransformFromProjections(sourceProjection, destinationProjection);\n return transformFunc(point);\n}\n\n/**\n * Add transforms to and from EPSG:4326 and EPSG:3857. This function is called\n * by when this module is executed and should only need to be called again after\n * `clearAllProjections()` is called (e.g. in tests).\n */\nexport function addCommon() {\n // Add transformations that don't alter coordinates to convert within set of\n // projections with equal meaning.\n addEquivalentProjections(EPSG3857_PROJECTIONS);\n addEquivalentProjections(EPSG4326_PROJECTIONS);\n // Add transformations to convert EPSG:4326 like coordinates to EPSG:3857 like\n // coordinates and back.\n addEquivalentTransforms(EPSG4326_PROJECTIONS, EPSG3857_PROJECTIONS, fromEPSG4326, toEPSG4326);\n}\n\naddCommon();\n","/**\n * @module ol/transform\n */\nimport {assert} from './asserts.js';\n\n\n/**\n * An array representing an affine 2d transformation for use with\n * {@link module:ol/transform} functions. The array has 6 elements.\n * @typedef {!Array.} Transform\n */\n\n\n/**\n * Collection of affine 2d transformation functions. The functions work on an\n * array of 6 elements. The element order is compatible with the [SVGMatrix\n * interface](https://developer.mozilla.org/en-US/docs/Web/API/SVGMatrix) and is\n * a subset (elements a to f) of a 3×3 matrix:\n * ```\n * [ a c e ]\n * [ b d f ]\n * [ 0 0 1 ]\n * ```\n */\n\n\n/**\n * @private\n * @type {module:ol/transform~Transform}\n */\nconst tmp_ = new Array(6);\n\n\n/**\n * Create an identity transform.\n * @return {!module:ol/transform~Transform} Identity transform.\n */\nexport function create() {\n return [1, 0, 0, 1, 0, 0];\n}\n\n\n/**\n * Resets the given transform to an identity transform.\n * @param {!module:ol/transform~Transform} transform Transform.\n * @return {!module:ol/transform~Transform} Transform.\n */\nexport function reset(transform) {\n return set(transform, 1, 0, 0, 1, 0, 0);\n}\n\n\n/**\n * Multiply the underlying matrices of two transforms and return the result in\n * the first transform.\n * @param {!module:ol/transform~Transform} transform1 Transform parameters of matrix 1.\n * @param {!module:ol/transform~Transform} transform2 Transform parameters of matrix 2.\n * @return {!module:ol/transform~Transform} transform1 multiplied with transform2.\n */\nexport function multiply(transform1, transform2) {\n const a1 = transform1[0];\n const b1 = transform1[1];\n const c1 = transform1[2];\n const d1 = transform1[3];\n const e1 = transform1[4];\n const f1 = transform1[5];\n const a2 = transform2[0];\n const b2 = transform2[1];\n const c2 = transform2[2];\n const d2 = transform2[3];\n const e2 = transform2[4];\n const f2 = transform2[5];\n\n transform1[0] = a1 * a2 + c1 * b2;\n transform1[1] = b1 * a2 + d1 * b2;\n transform1[2] = a1 * c2 + c1 * d2;\n transform1[3] = b1 * c2 + d1 * d2;\n transform1[4] = a1 * e2 + c1 * f2 + e1;\n transform1[5] = b1 * e2 + d1 * f2 + f1;\n\n return transform1;\n}\n\n/**\n * Set the transform components a-f on a given transform.\n * @param {!module:ol/transform~Transform} transform Transform.\n * @param {number} a The a component of the transform.\n * @param {number} b The b component of the transform.\n * @param {number} c The c component of the transform.\n * @param {number} d The d component of the transform.\n * @param {number} e The e component of the transform.\n * @param {number} f The f component of the transform.\n * @return {!module:ol/transform~Transform} Matrix with transform applied.\n */\nexport function set(transform, a, b, c, d, e, f) {\n transform[0] = a;\n transform[1] = b;\n transform[2] = c;\n transform[3] = d;\n transform[4] = e;\n transform[5] = f;\n return transform;\n}\n\n\n/**\n * Set transform on one matrix from another matrix.\n * @param {!module:ol/transform~Transform} transform1 Matrix to set transform to.\n * @param {!module:ol/transform~Transform} transform2 Matrix to set transform from.\n * @return {!module:ol/transform~Transform} transform1 with transform from transform2 applied.\n */\nexport function setFromArray(transform1, transform2) {\n transform1[0] = transform2[0];\n transform1[1] = transform2[1];\n transform1[2] = transform2[2];\n transform1[3] = transform2[3];\n transform1[4] = transform2[4];\n transform1[5] = transform2[5];\n return transform1;\n}\n\n\n/**\n * Transforms the given coordinate with the given transform returning the\n * resulting, transformed coordinate. The coordinate will be modified in-place.\n *\n * @param {module:ol/transform~Transform} transform The transformation.\n * @param {module:ol/coordinate~Coordinate|module:ol~Pixel} coordinate The coordinate to transform.\n * @return {module:ol/coordinate~Coordinate|module:ol~Pixel} return coordinate so that operations can be\n * chained together.\n */\nexport function apply(transform, coordinate) {\n const x = coordinate[0];\n const y = coordinate[1];\n coordinate[0] = transform[0] * x + transform[2] * y + transform[4];\n coordinate[1] = transform[1] * x + transform[3] * y + transform[5];\n return coordinate;\n}\n\n\n/**\n * Applies rotation to the given transform.\n * @param {!module:ol/transform~Transform} transform Transform.\n * @param {number} angle Angle in radians.\n * @return {!module:ol/transform~Transform} The rotated transform.\n */\nexport function rotate(transform, angle) {\n const cos = Math.cos(angle);\n const sin = Math.sin(angle);\n return multiply(transform, set(tmp_, cos, sin, -sin, cos, 0, 0));\n}\n\n\n/**\n * Applies scale to a given transform.\n * @param {!module:ol/transform~Transform} transform Transform.\n * @param {number} x Scale factor x.\n * @param {number} y Scale factor y.\n * @return {!module:ol/transform~Transform} The scaled transform.\n */\nexport function scale(transform, x, y) {\n return multiply(transform, set(tmp_, x, 0, 0, y, 0, 0));\n}\n\n\n/**\n * Applies translation to the given transform.\n * @param {!module:ol/transform~Transform} transform Transform.\n * @param {number} dx Translation x.\n * @param {number} dy Translation y.\n * @return {!module:ol/transform~Transform} The translated transform.\n */\nexport function translate(transform, dx, dy) {\n return multiply(transform, set(tmp_, 1, 0, 0, 1, dx, dy));\n}\n\n\n/**\n * Creates a composite transform given an initial translation, scale, rotation, and\n * final translation (in that order only, not commutative).\n * @param {!module:ol/transform~Transform} transform The transform (will be modified in place).\n * @param {number} dx1 Initial translation x.\n * @param {number} dy1 Initial translation y.\n * @param {number} sx Scale factor x.\n * @param {number} sy Scale factor y.\n * @param {number} angle Rotation (in counter-clockwise radians).\n * @param {number} dx2 Final translation x.\n * @param {number} dy2 Final translation y.\n * @return {!module:ol/transform~Transform} The composite transform.\n */\nexport function compose(transform, dx1, dy1, sx, sy, angle, dx2, dy2) {\n const sin = Math.sin(angle);\n const cos = Math.cos(angle);\n transform[0] = sx * cos;\n transform[1] = sy * sin;\n transform[2] = -sx * sin;\n transform[3] = sy * cos;\n transform[4] = dx2 * sx * cos - dy2 * sx * sin + dx1;\n transform[5] = dx2 * sy * sin + dy2 * sy * cos + dy1;\n return transform;\n}\n\n\n/**\n * Invert the given transform.\n * @param {!module:ol/transform~Transform} transform Transform.\n * @return {!module:ol/transform~Transform} Inverse of the transform.\n */\nexport function invert(transform) {\n const det = determinant(transform);\n assert(det !== 0, 32); // Transformation matrix cannot be inverted\n\n const a = transform[0];\n const b = transform[1];\n const c = transform[2];\n const d = transform[3];\n const e = transform[4];\n const f = transform[5];\n\n transform[0] = d / det;\n transform[1] = -b / det;\n transform[2] = -c / det;\n transform[3] = a / det;\n transform[4] = (c * f - d * e) / det;\n transform[5] = -(a * f - b * e) / det;\n\n return transform;\n}\n\n\n/**\n * Returns the determinant of the given matrix.\n * @param {!module:ol/transform~Transform} mat Matrix.\n * @return {number} Determinant.\n */\nexport function determinant(mat) {\n return mat[0] * mat[3] - mat[1] * mat[2];\n}\n","/**\n * @module ol/geom/Geometry\n */\nimport {inherits} from '../util.js';\nimport BaseObject from '../Object.js';\nimport {createEmpty, getHeight, returnOrUpdate} from '../extent.js';\nimport {FALSE} from '../functions.js';\nimport {transform2D} from '../geom/flat/transform.js';\nimport {get as getProjection, getTransform} from '../proj.js';\nimport Units from '../proj/Units.js';\nimport {create as createTransform, compose as composeTransform} from '../transform.js';\n\n\n/**\n * @classdesc\n * Abstract base class; normally only used for creating subclasses and not\n * instantiated in apps.\n * Base class for vector geometries.\n *\n * To get notified of changes to the geometry, register a listener for the\n * generic `change` event on your geometry instance.\n *\n * @constructor\n * @abstract\n * @extends {module:ol/Object}\n * @api\n */\nconst Geometry = function() {\n\n BaseObject.call(this);\n\n /**\n * @private\n * @type {module:ol/extent~Extent}\n */\n this.extent_ = createEmpty();\n\n /**\n * @private\n * @type {number}\n */\n this.extentRevision_ = -1;\n\n /**\n * @protected\n * @type {Object.}\n */\n this.simplifiedGeometryCache = {};\n\n /**\n * @protected\n * @type {number}\n */\n this.simplifiedGeometryMaxMinSquaredTolerance = 0;\n\n /**\n * @protected\n * @type {number}\n */\n this.simplifiedGeometryRevision = 0;\n\n};\n\ninherits(Geometry, BaseObject);\n\n\n/**\n * @type {module:ol/transform~Transform}\n */\nconst tmpTransform = createTransform();\n\n\n/**\n * Make a complete copy of the geometry.\n * @abstract\n * @return {!module:ol/geom/Geometry} Clone.\n */\nGeometry.prototype.clone = function() {};\n\n\n/**\n * @abstract\n * @param {number} x X.\n * @param {number} y Y.\n * @param {module:ol/coordinate~Coordinate} closestPoint Closest point.\n * @param {number} minSquaredDistance Minimum squared distance.\n * @return {number} Minimum squared distance.\n */\nGeometry.prototype.closestPointXY = function(x, y, closestPoint, minSquaredDistance) {};\n\n\n/**\n * Return the closest point of the geometry to the passed point as\n * {@link module:ol/coordinate~Coordinate coordinate}.\n * @param {module:ol/coordinate~Coordinate} point Point.\n * @param {module:ol/coordinate~Coordinate=} opt_closestPoint Closest point.\n * @return {module:ol/coordinate~Coordinate} Closest point.\n * @api\n */\nGeometry.prototype.getClosestPoint = function(point, opt_closestPoint) {\n const closestPoint = opt_closestPoint ? opt_closestPoint : [NaN, NaN];\n this.closestPointXY(point[0], point[1], closestPoint, Infinity);\n return closestPoint;\n};\n\n\n/**\n * Returns true if this geometry includes the specified coordinate. If the\n * coordinate is on the boundary of the geometry, returns false.\n * @param {module:ol/coordinate~Coordinate} coordinate Coordinate.\n * @return {boolean} Contains coordinate.\n * @api\n */\nGeometry.prototype.intersectsCoordinate = function(coordinate) {\n return this.containsXY(coordinate[0], coordinate[1]);\n};\n\n\n/**\n * @abstract\n * @param {module:ol/extent~Extent} extent Extent.\n * @protected\n * @return {module:ol/extent~Extent} extent Extent.\n */\nGeometry.prototype.computeExtent = function(extent) {};\n\n\n/**\n * @param {number} x X.\n * @param {number} y Y.\n * @return {boolean} Contains (x, y).\n */\nGeometry.prototype.containsXY = FALSE;\n\n\n/**\n * Get the extent of the geometry.\n * @param {module:ol/extent~Extent=} opt_extent Extent.\n * @return {module:ol/extent~Extent} extent Extent.\n * @api\n */\nGeometry.prototype.getExtent = function(opt_extent) {\n if (this.extentRevision_ != this.getRevision()) {\n this.extent_ = this.computeExtent(this.extent_);\n this.extentRevision_ = this.getRevision();\n }\n return returnOrUpdate(this.extent_, opt_extent);\n};\n\n\n/**\n * Rotate the geometry around a given coordinate. This modifies the geometry\n * coordinates in place.\n * @abstract\n * @param {number} angle Rotation angle in radians.\n * @param {module:ol/coordinate~Coordinate} anchor The rotation center.\n * @api\n */\nGeometry.prototype.rotate = function(angle, anchor) {};\n\n\n/**\n * Scale the geometry (with an optional origin). This modifies the geometry\n * coordinates in place.\n * @abstract\n * @param {number} sx The scaling factor in the x-direction.\n * @param {number=} opt_sy The scaling factor in the y-direction (defaults to\n * sx).\n * @param {module:ol/coordinate~Coordinate=} opt_anchor The scale origin (defaults to the center\n * of the geometry extent).\n * @api\n */\nGeometry.prototype.scale = function(sx, opt_sy, opt_anchor) {};\n\n\n/**\n * Create a simplified version of this geometry. For linestrings, this uses\n * the the {@link\n * https://en.wikipedia.org/wiki/Ramer-Douglas-Peucker_algorithm\n * Douglas Peucker} algorithm. For polygons, a quantization-based\n * simplification is used to preserve topology.\n * @function\n * @param {number} tolerance The tolerance distance for simplification.\n * @return {module:ol/geom/Geometry} A new, simplified version of the original\n * geometry.\n * @api\n */\nGeometry.prototype.simplify = function(tolerance) {\n return this.getSimplifiedGeometry(tolerance * tolerance);\n};\n\n\n/**\n * Create a simplified version of this geometry using the Douglas Peucker\n * algorithm.\n * @see https://en.wikipedia.org/wiki/Ramer-Douglas-Peucker_algorithm\n * @abstract\n * @param {number} squaredTolerance Squared tolerance.\n * @return {module:ol/geom/Geometry} Simplified geometry.\n */\nGeometry.prototype.getSimplifiedGeometry = function(squaredTolerance) {};\n\n\n/**\n * Get the type of this geometry.\n * @abstract\n * @return {module:ol/geom/GeometryType} Geometry type.\n */\nGeometry.prototype.getType = function() {};\n\n\n/**\n * Apply a transform function to each coordinate of the geometry.\n * The geometry is modified in place.\n * If you do not want the geometry modified in place, first `clone()` it and\n * then use this function on the clone.\n * @abstract\n * @param {module:ol/proj~TransformFunction} transformFn Transform.\n */\nGeometry.prototype.applyTransform = function(transformFn) {};\n\n\n/**\n * Test if the geometry and the passed extent intersect.\n * @abstract\n * @param {module:ol/extent~Extent} extent Extent.\n * @return {boolean} `true` if the geometry and the extent intersect.\n */\nGeometry.prototype.intersectsExtent = function(extent) {};\n\n\n/**\n * Translate the geometry. This modifies the geometry coordinates in place. If\n * instead you want a new geometry, first `clone()` this geometry.\n * @abstract\n * @param {number} deltaX Delta X.\n * @param {number} deltaY Delta Y.\n */\nGeometry.prototype.translate = function(deltaX, deltaY) {};\n\n\n/**\n * Transform each coordinate of the geometry from one coordinate reference\n * system to another. The geometry is modified in place.\n * For example, a line will be transformed to a line and a circle to a circle.\n * If you do not want the geometry modified in place, first `clone()` it and\n * then use this function on the clone.\n *\n * @param {module:ol/proj~ProjectionLike} source The current projection. Can be a\n * string identifier or a {@link module:ol/proj/Projection~Projection} object.\n * @param {module:ol/proj~ProjectionLike} destination The desired projection. Can be a\n * string identifier or a {@link module:ol/proj/Projection~Projection} object.\n * @return {module:ol/geom/Geometry} This geometry. Note that original geometry is\n * modified in place.\n * @api\n */\nGeometry.prototype.transform = function(source, destination) {\n source = getProjection(source);\n const transformFn = source.getUnits() == Units.TILE_PIXELS ?\n function(inCoordinates, outCoordinates, stride) {\n const pixelExtent = source.getExtent();\n const projectedExtent = source.getWorldExtent();\n const scale = getHeight(projectedExtent) / getHeight(pixelExtent);\n composeTransform(tmpTransform,\n projectedExtent[0], projectedExtent[3],\n scale, -scale, 0,\n 0, 0);\n transform2D(inCoordinates, 0, inCoordinates.length, stride,\n tmpTransform, outCoordinates);\n return getTransform(source, destination)(inCoordinates, outCoordinates, stride);\n } :\n getTransform(source, destination);\n this.applyTransform(transformFn);\n return this;\n};\nexport default Geometry;\n","/**\n * @module ol/color\n */\nimport {assert} from './asserts.js';\nimport {clamp} from './math.js';\n\n\n/**\n * A color represented as a short array [red, green, blue, alpha].\n * red, green, and blue should be integers in the range 0..255 inclusive.\n * alpha should be a float in the range 0..1 inclusive. If no alpha value is\n * given then `1` will be used.\n * @typedef {Array.} Color\n * @api\n */\n\n\n/**\n * This RegExp matches # followed by 3, 4, 6, or 8 hex digits.\n * @const\n * @type {RegExp}\n * @private\n */\nconst HEX_COLOR_RE_ = /^#([a-f0-9]{3}|[a-f0-9]{4}(?:[a-f0-9]{2}){0,2})$/i;\n\n\n/**\n * Regular expression for matching potential named color style strings.\n * @const\n * @type {RegExp}\n * @private\n */\nconst NAMED_COLOR_RE_ = /^([a-z]*)$/i;\n\n\n/**\n * Return the color as an rgba string.\n * @param {module:ol/color~Color|string} color Color.\n * @return {string} Rgba string.\n * @api\n */\nexport function asString(color) {\n if (typeof color === 'string') {\n return color;\n } else {\n return toString(color);\n }\n}\n\n/**\n * Return named color as an rgba string.\n * @param {string} color Named color.\n * @return {string} Rgb string.\n */\nfunction fromNamed(color) {\n const el = document.createElement('div');\n el.style.color = color;\n if (el.style.color !== '') {\n document.body.appendChild(el);\n const rgb = getComputedStyle(el).color;\n document.body.removeChild(el);\n return rgb;\n } else {\n return '';\n }\n}\n\n\n/**\n * @param {string} s String.\n * @return {module:ol/color~Color} Color.\n */\nexport const fromString = (\n function() {\n\n // We maintain a small cache of parsed strings. To provide cheap LRU-like\n // semantics, whenever the cache grows too large we simply delete an\n // arbitrary 25% of the entries.\n\n /**\n * @const\n * @type {number}\n */\n const MAX_CACHE_SIZE = 1024;\n\n /**\n * @type {Object.}\n */\n const cache = {};\n\n /**\n * @type {number}\n */\n let cacheSize = 0;\n\n return (\n /**\n * @param {string} s String.\n * @return {module:ol/color~Color} Color.\n */\n function(s) {\n let color;\n if (cache.hasOwnProperty(s)) {\n color = cache[s];\n } else {\n if (cacheSize >= MAX_CACHE_SIZE) {\n let i = 0;\n for (const key in cache) {\n if ((i++ & 3) === 0) {\n delete cache[key];\n --cacheSize;\n }\n }\n }\n color = fromStringInternal_(s);\n cache[s] = color;\n ++cacheSize;\n }\n return color;\n }\n );\n\n })();\n\n/**\n * Return the color as an array. This function maintains a cache of calculated\n * arrays which means the result should not be modified.\n * @param {module:ol/color~Color|string} color Color.\n * @return {module:ol/color~Color} Color.\n * @api\n */\nexport function asArray(color) {\n if (Array.isArray(color)) {\n return color;\n } else {\n return fromString(/** @type {string} */ (color));\n }\n}\n\n/**\n * @param {string} s String.\n * @private\n * @return {module:ol/color~Color} Color.\n */\nfunction fromStringInternal_(s) {\n let r, g, b, a, color;\n\n if (NAMED_COLOR_RE_.exec(s)) {\n s = fromNamed(s);\n }\n\n if (HEX_COLOR_RE_.exec(s)) { // hex\n const n = s.length - 1; // number of hex digits\n let d; // number of digits per channel\n if (n <= 4) {\n d = 1;\n } else {\n d = 2;\n }\n const hasAlpha = n === 4 || n === 8;\n r = parseInt(s.substr(1 + 0 * d, d), 16);\n g = parseInt(s.substr(1 + 1 * d, d), 16);\n b = parseInt(s.substr(1 + 2 * d, d), 16);\n if (hasAlpha) {\n a = parseInt(s.substr(1 + 3 * d, d), 16);\n } else {\n a = 255;\n }\n if (d == 1) {\n r = (r << 4) + r;\n g = (g << 4) + g;\n b = (b << 4) + b;\n if (hasAlpha) {\n a = (a << 4) + a;\n }\n }\n color = [r, g, b, a / 255];\n } else if (s.indexOf('rgba(') == 0) { // rgba()\n color = s.slice(5, -1).split(',').map(Number);\n normalize(color);\n } else if (s.indexOf('rgb(') == 0) { // rgb()\n color = s.slice(4, -1).split(',').map(Number);\n color.push(1);\n normalize(color);\n } else {\n assert(false, 14); // Invalid color\n }\n return (\n /** @type {module:ol/color~Color} */ (color)\n );\n}\n\n\n/**\n * TODO this function is only used in the test, we probably shouldn't export it\n * @param {module:ol/color~Color} color Color.\n * @return {module:ol/color~Color} Clamped color.\n */\nexport function normalize(color) {\n color[0] = clamp((color[0] + 0.5) | 0, 0, 255);\n color[1] = clamp((color[1] + 0.5) | 0, 0, 255);\n color[2] = clamp((color[2] + 0.5) | 0, 0, 255);\n color[3] = clamp(color[3], 0, 1);\n return color;\n}\n\n\n/**\n * @param {module:ol/color~Color} color Color.\n * @return {string} String.\n */\nexport function toString(color) {\n let r = color[0];\n if (r != (r | 0)) {\n r = (r + 0.5) | 0;\n }\n let g = color[1];\n if (g != (g | 0)) {\n g = (g + 0.5) | 0;\n }\n let b = color[2];\n if (b != (b | 0)) {\n b = (b + 0.5) | 0;\n }\n const a = color[3] === undefined ? 1 : color[3];\n return 'rgba(' + r + ',' + g + ',' + b + ',' + a + ')';\n}\n","/**\n * @module ol/colorlike\n */\nimport {toString} from './color.js';\n\n\n/**\n * A type accepted by CanvasRenderingContext2D.fillStyle\n * or CanvasRenderingContext2D.strokeStyle.\n * Represents a color, pattern, or gradient. The origin for patterns and\n * gradients as fill style is an increment of 512 css pixels from map coordinate\n * `[0, 0]`. For seamless repeat patterns, width and height of the pattern image\n * must be a factor of two (2, 4, 8, ..., 512).\n *\n * @typedef {string|CanvasPattern|CanvasGradient} ColorLike\n * @api\n */\n\n\n/**\n * @param {module:ol/color~Color|module:ol/colorlike~ColorLike} color Color.\n * @return {module:ol/colorlike~ColorLike} The color as an {@link ol/colorlike~ColorLike}.\n * @api\n */\nexport function asColorLike(color) {\n if (isColorLike(color)) {\n return /** @type {string|CanvasPattern|CanvasGradient} */ (color);\n } else {\n return toString(/** @type {module:ol/color~Color} */ (color));\n }\n}\n\n\n/**\n * @param {?} color The value that is potentially an {@link ol/colorlike~ColorLike}.\n * @return {boolean} The color is an {@link ol/colorlike~ColorLike}.\n */\nexport function isColorLike(color) {\n return (\n typeof color === 'string' ||\n color instanceof CanvasPattern ||\n color instanceof CanvasGradient\n );\n}\n","/**\n * @module ol/dom\n */\n\n\n/**\n * Create an html canvas element and returns its 2d context.\n * @param {number=} opt_width Canvas width.\n * @param {number=} opt_height Canvas height.\n * @return {CanvasRenderingContext2D} The context.\n */\nexport function createCanvasContext2D(opt_width, opt_height) {\n const canvas = /** @type {HTMLCanvasElement} */ (document.createElement('CANVAS'));\n if (opt_width) {\n canvas.width = opt_width;\n }\n if (opt_height) {\n canvas.height = opt_height;\n }\n return /** @type {CanvasRenderingContext2D} */ (canvas.getContext('2d'));\n}\n\n\n/**\n * Get the current computed width for the given element including margin,\n * padding and border.\n * Equivalent to jQuery's `$(el).outerWidth(true)`.\n * @param {!Element} element Element.\n * @return {number} The width.\n */\nexport function outerWidth(element) {\n let width = element.offsetWidth;\n const style = getComputedStyle(element);\n width += parseInt(style.marginLeft, 10) + parseInt(style.marginRight, 10);\n\n return width;\n}\n\n\n/**\n * Get the current computed height for the given element including margin,\n * padding and border.\n * Equivalent to jQuery's `$(el).outerHeight(true)`.\n * @param {!Element} element Element.\n * @return {number} The height.\n */\nexport function outerHeight(element) {\n let height = element.offsetHeight;\n const style = getComputedStyle(element);\n height += parseInt(style.marginTop, 10) + parseInt(style.marginBottom, 10);\n\n return height;\n}\n\n/**\n * @param {Node} newNode Node to replace old node\n * @param {Node} oldNode The node to be replaced\n */\nexport function replaceNode(newNode, oldNode) {\n const parent = oldNode.parentNode;\n if (parent) {\n parent.replaceChild(newNode, oldNode);\n }\n}\n\n/**\n * @param {Node} node The node to remove.\n * @returns {Node} The node that was removed or null.\n */\nexport function removeNode(node) {\n return node && node.parentNode ? node.parentNode.removeChild(node) : null;\n}\n\n/**\n * @param {Node} node The node to remove the children from.\n */\nexport function removeChildren(node) {\n while (node.lastChild) {\n node.removeChild(node.lastChild);\n }\n}\n","/**\n * @module ol/webgl\n */\n\n\n/**\n * Constants taken from goog.webgl\n */\n\n\n/**\n * @const\n * @type {number}\n */\nexport const ONE = 1;\n\n\n/**\n * @const\n * @type {number}\n */\nexport const SRC_ALPHA = 0x0302;\n\n\n/**\n * @const\n * @type {number}\n */\nexport const COLOR_ATTACHMENT0 = 0x8CE0;\n\n\n/**\n * @const\n * @type {number}\n */\nexport const COLOR_BUFFER_BIT = 0x00004000;\n\n\n/**\n * @const\n * @type {number}\n */\nexport const TRIANGLES = 0x0004;\n\n\n/**\n * @const\n * @type {number}\n */\nexport const TRIANGLE_STRIP = 0x0005;\n\n\n/**\n * @const\n * @type {number}\n */\nexport const ONE_MINUS_SRC_ALPHA = 0x0303;\n\n\n/**\n * @const\n * @type {number}\n */\nexport const ARRAY_BUFFER = 0x8892;\n\n\n/**\n * @const\n * @type {number}\n */\nexport const ELEMENT_ARRAY_BUFFER = 0x8893;\n\n\n/**\n * @const\n * @type {number}\n */\nexport const STREAM_DRAW = 0x88E0;\n\n\n/**\n * @const\n * @type {number}\n */\nexport const STATIC_DRAW = 0x88E4;\n\n\n/**\n * @const\n * @type {number}\n */\nexport const DYNAMIC_DRAW = 0x88E8;\n\n\n/**\n * @const\n * @type {number}\n */\nexport const CULL_FACE = 0x0B44;\n\n\n/**\n * @const\n * @type {number}\n */\nexport const BLEND = 0x0BE2;\n\n\n/**\n * @const\n * @type {number}\n */\nexport const STENCIL_TEST = 0x0B90;\n\n\n/**\n * @const\n * @type {number}\n */\nexport const DEPTH_TEST = 0x0B71;\n\n\n/**\n * @const\n * @type {number}\n */\nexport const SCISSOR_TEST = 0x0C11;\n\n\n/**\n * @const\n * @type {number}\n */\nexport const UNSIGNED_BYTE = 0x1401;\n\n\n/**\n * @const\n * @type {number}\n */\nexport const UNSIGNED_SHORT = 0x1403;\n\n\n/**\n * @const\n * @type {number}\n */\nexport const UNSIGNED_INT = 0x1405;\n\n\n/**\n * @const\n * @type {number}\n */\nexport const FLOAT = 0x1406;\n\n\n/**\n * @const\n * @type {number}\n */\nexport const RGBA = 0x1908;\n\n\n/**\n * @const\n * @type {number}\n */\nexport const FRAGMENT_SHADER = 0x8B30;\n\n\n/**\n * @const\n * @type {number}\n */\nexport const VERTEX_SHADER = 0x8B31;\n\n\n/**\n * @const\n * @type {number}\n */\nexport const LINK_STATUS = 0x8B82;\n\n\n/**\n * @const\n * @type {number}\n */\nexport const LINEAR = 0x2601;\n\n\n/**\n * @const\n * @type {number}\n */\nexport const TEXTURE_MAG_FILTER = 0x2800;\n\n\n/**\n * @const\n * @type {number}\n */\nexport const TEXTURE_MIN_FILTER = 0x2801;\n\n\n/**\n * @const\n * @type {number}\n */\nexport const TEXTURE_WRAP_S = 0x2802;\n\n\n/**\n * @const\n * @type {number}\n */\nexport const TEXTURE_WRAP_T = 0x2803;\n\n\n/**\n * @const\n * @type {number}\n */\nexport const TEXTURE_2D = 0x0DE1;\n\n\n/**\n * @const\n * @type {number}\n */\nexport const TEXTURE0 = 0x84C0;\n\n\n/**\n * @const\n * @type {number}\n */\nexport const CLAMP_TO_EDGE = 0x812F;\n\n\n/**\n * @const\n * @type {number}\n */\nexport const COMPILE_STATUS = 0x8B81;\n\n\n/**\n * @const\n * @type {number}\n */\nexport const FRAMEBUFFER = 0x8D40;\n\n\n/** end of goog.webgl constants\n */\n\n\n/**\n * @const\n * @type {Array.}\n */\nconst CONTEXT_IDS = [\n 'experimental-webgl',\n 'webgl',\n 'webkit-3d',\n 'moz-webgl'\n];\n\n\n/**\n * @param {HTMLCanvasElement} canvas Canvas.\n * @param {Object=} opt_attributes Attributes.\n * @return {WebGLRenderingContext} WebGL rendering context.\n */\nexport function getContext(canvas, opt_attributes) {\n const ii = CONTEXT_IDS.length;\n for (let i = 0; i < ii; ++i) {\n try {\n const context = canvas.getContext(CONTEXT_IDS[i], opt_attributes);\n if (context) {\n return /** @type {!WebGLRenderingContext} */ (context);\n }\n } catch (e) {\n // pass\n }\n }\n return null;\n}\n\n\n/**\n * Include debuggable shader sources. Default is `true`. This should be set to\n * `false` for production builds.\n * @type {boolean}\n */\nexport const DEBUG = true;\n\n\n/**\n * The maximum supported WebGL texture size in pixels. If WebGL is not\n * supported, the value is set to `undefined`.\n * @type {number|undefined}\n */\nlet MAX_TEXTURE_SIZE; // value is set below\n\n\n/**\n * List of supported WebGL extensions.\n * @type {Array.}\n */\nlet EXTENSIONS; // value is set below\n\n\n/**\n * True if both OpenLayers and browser support WebGL.\n * @const ol/has.WEBGL\n * @type {boolean}\n * @api\n */\nlet HAS = false;\n\n//TODO Remove side effects\nif (typeof window !== 'undefined' && 'WebGLRenderingContext' in window) {\n try {\n const canvas = /** @type {HTMLCanvasElement} */ (document.createElement('CANVAS'));\n const gl = getContext(canvas, {failIfMajorPerformanceCaveat: true});\n if (gl) {\n HAS = true;\n MAX_TEXTURE_SIZE = /** @type {number} */ (gl.getParameter(gl.MAX_TEXTURE_SIZE));\n EXTENSIONS = gl.getSupportedExtensions();\n }\n } catch (e) {\n // pass\n }\n}\n\nexport {HAS, MAX_TEXTURE_SIZE, EXTENSIONS};\n","/**\n * @module ol/has\n */\n\nconst ua = typeof navigator !== 'undefined' ?\n navigator.userAgent.toLowerCase() : '';\n\n/**\n * User agent string says we are dealing with Firefox as browser.\n * @type {boolean}\n */\nexport const FIREFOX = ua.indexOf('firefox') !== -1;\n\n/**\n * User agent string says we are dealing with Safari as browser.\n * @type {boolean}\n */\nexport const SAFARI = ua.indexOf('safari') !== -1 && ua.indexOf('chrom') == -1;\n\n/**\n * User agent string says we are dealing with a WebKit engine.\n * @type {boolean}\n */\nexport const WEBKIT = ua.indexOf('webkit') !== -1 && ua.indexOf('edge') == -1;\n\n/**\n * User agent string says we are dealing with a Mac as platform.\n * @type {boolean}\n */\nexport const MAC = ua.indexOf('macintosh') !== -1;\n\n\n/**\n * The ratio between physical pixels and device-independent pixels\n * (dips) on the device (`window.devicePixelRatio`).\n * @const\n * @type {number}\n * @api\n */\nexport const DEVICE_PIXEL_RATIO = window.devicePixelRatio || 1;\n\n\n/**\n * True if the browser's Canvas implementation implements {get,set}LineDash.\n * @type {boolean}\n */\nexport const CANVAS_LINE_DASH = function() {\n let has = false;\n try {\n has = !!document.createElement('CANVAS').getContext('2d').setLineDash;\n } catch (e) {\n // pass\n }\n return has;\n}();\n\n\n/**\n * Is HTML5 geolocation supported in the current browser?\n * @const\n * @type {boolean}\n * @api\n */\nexport const GEOLOCATION = 'geolocation' in navigator;\n\n\n/**\n * True if browser supports touch events.\n * @const\n * @type {boolean}\n * @api\n */\nexport const TOUCH = 'ontouchstart' in window;\n\n\n/**\n * True if browser supports pointer events.\n * @const\n * @type {boolean}\n */\nexport const POINTER = 'PointerEvent' in window;\n\n\n/**\n * True if browser supports ms pointer events (IE 10).\n * @const\n * @type {boolean}\n */\nexport const MSPOINTER = !!(navigator.msPointerEnabled);\n\n\nexport {HAS as WEBGL} from './webgl.js';\n","/**\n * @module ol/css\n */\n\n\n/**\n * The CSS class for hidden feature.\n *\n * @const\n * @type {string}\n */\nexport const CLASS_HIDDEN = 'ol-hidden';\n\n\n/**\n * The CSS class that we'll give the DOM elements to have them selectable.\n *\n * @const\n * @type {string}\n */\nexport const CLASS_SELECTABLE = 'ol-selectable';\n\n\n/**\n * The CSS class that we'll give the DOM elements to have them unselectable.\n *\n * @const\n * @type {string}\n */\nexport const CLASS_UNSELECTABLE = 'ol-unselectable';\n\n\n/**\n * The CSS class for unsupported feature.\n *\n * @const\n * @type {string}\n */\nexport const CLASS_UNSUPPORTED = 'ol-unsupported';\n\n\n/**\n * The CSS class for controls.\n *\n * @const\n * @type {string}\n */\nexport const CLASS_CONTROL = 'ol-control';\n\n\n/**\n * The CSS class that we'll give the DOM elements that are collapsed, i.e.\n * to those elements which usually can be expanded.\n *\n * @const\n * @type {string}\n */\nexport const CLASS_COLLAPSED = 'ol-collapsed';\n\n\n/**\n * Get the list of font families from a font spec. Note that this doesn't work\n * for font families that have commas in them.\n * @param {string} The CSS font property.\n * @return {Object.} The font families (or null if the input spec is invalid).\n */\nexport const getFontFamilies = (function() {\n let style;\n const cache = {};\n return function(font) {\n if (!style) {\n style = document.createElement('div').style;\n }\n if (!(font in cache)) {\n style.font = font;\n const family = style.fontFamily;\n style.font = '';\n if (!family) {\n return null;\n }\n cache[font] = family.split(/,\\s?/);\n }\n return cache[font];\n };\n})();\n","/**\n * @module ol/ImageState\n */\n\n/**\n * @enum {number}\n */\nexport default {\n IDLE: 0,\n LOADING: 1,\n LOADED: 2,\n ERROR: 3\n};\n","/**\n * @module ol/structs/LRUCache\n */\nimport {inherits} from '../util.js';\nimport {assert} from '../asserts.js';\nimport EventTarget from '../events/EventTarget.js';\nimport EventType from '../events/EventType.js';\n\n\n/**\n * @typedef {Object} Entry\n * @property {string} key_\n * @property {Object} newer\n * @property {Object} older\n * @property {*} value_\n */\n\n\n/**\n * Implements a Least-Recently-Used cache where the keys do not conflict with\n * Object's properties (e.g. 'hasOwnProperty' is not allowed as a key). Expiring\n * items from the cache is the responsibility of the user.\n * @constructor\n * @extends {module:ol/events/EventTarget}\n * @fires module:ol/events/Event~Event\n * @struct\n * @template T\n * @param {number=} opt_highWaterMark High water mark.\n */\nconst LRUCache = function(opt_highWaterMark) {\n\n EventTarget.call(this);\n\n /**\n * @type {number}\n */\n this.highWaterMark = opt_highWaterMark !== undefined ? opt_highWaterMark : 2048;\n\n /**\n * @private\n * @type {number}\n */\n this.count_ = 0;\n\n /**\n * @private\n * @type {!Object.}\n */\n this.entries_ = {};\n\n /**\n * @private\n * @type {?module:ol/structs/LRUCache~Entry}\n */\n this.oldest_ = null;\n\n /**\n * @private\n * @type {?module:ol/structs/LRUCache~Entry}\n */\n this.newest_ = null;\n\n};\n\ninherits(LRUCache, EventTarget);\n\n\n/**\n * @return {boolean} Can expire cache.\n */\nLRUCache.prototype.canExpireCache = function() {\n return this.getCount() > this.highWaterMark;\n};\n\n\n/**\n * FIXME empty description for jsdoc\n */\nLRUCache.prototype.clear = function() {\n this.count_ = 0;\n this.entries_ = {};\n this.oldest_ = null;\n this.newest_ = null;\n this.dispatchEvent(EventType.CLEAR);\n};\n\n\n/**\n * @param {string} key Key.\n * @return {boolean} Contains key.\n */\nLRUCache.prototype.containsKey = function(key) {\n return this.entries_.hasOwnProperty(key);\n};\n\n\n/**\n * @param {function(this: S, T, string, module:ol/structs/LRUCache): ?} f The function\n * to call for every entry from the oldest to the newer. This function takes\n * 3 arguments (the entry value, the entry key and the LRUCache object).\n * The return value is ignored.\n * @param {S=} opt_this The object to use as `this` in `f`.\n * @template S\n */\nLRUCache.prototype.forEach = function(f, opt_this) {\n let entry = this.oldest_;\n while (entry) {\n f.call(opt_this, entry.value_, entry.key_, this);\n entry = entry.newer;\n }\n};\n\n\n/**\n * @param {string} key Key.\n * @return {T} Value.\n */\nLRUCache.prototype.get = function(key) {\n const entry = this.entries_[key];\n assert(entry !== undefined,\n 15); // Tried to get a value for a key that does not exist in the cache\n if (entry === this.newest_) {\n return entry.value_;\n } else if (entry === this.oldest_) {\n this.oldest_ = /** @type {module:ol/structs/LRUCache~Entry} */ (this.oldest_.newer);\n this.oldest_.older = null;\n } else {\n entry.newer.older = entry.older;\n entry.older.newer = entry.newer;\n }\n entry.newer = null;\n entry.older = this.newest_;\n this.newest_.newer = entry;\n this.newest_ = entry;\n return entry.value_;\n};\n\n\n/**\n * Remove an entry from the cache.\n * @param {string} key The entry key.\n * @return {T} The removed entry.\n */\nLRUCache.prototype.remove = function(key) {\n const entry = this.entries_[key];\n assert(entry !== undefined, 15); // Tried to get a value for a key that does not exist in the cache\n if (entry === this.newest_) {\n this.newest_ = /** @type {module:ol/structs/LRUCache~Entry} */ (entry.older);\n if (this.newest_) {\n this.newest_.newer = null;\n }\n } else if (entry === this.oldest_) {\n this.oldest_ = /** @type {module:ol/structs/LRUCache~Entry} */ (entry.newer);\n if (this.oldest_) {\n this.oldest_.older = null;\n }\n } else {\n entry.newer.older = entry.older;\n entry.older.newer = entry.newer;\n }\n delete this.entries_[key];\n --this.count_;\n return entry.value_;\n};\n\n\n/**\n * @return {number} Count.\n */\nLRUCache.prototype.getCount = function() {\n return this.count_;\n};\n\n\n/**\n * @return {Array.} Keys.\n */\nLRUCache.prototype.getKeys = function() {\n const keys = new Array(this.count_);\n let i = 0;\n let entry;\n for (entry = this.newest_; entry; entry = entry.older) {\n keys[i++] = entry.key_;\n }\n return keys;\n};\n\n\n/**\n * @return {Array.} Values.\n */\nLRUCache.prototype.getValues = function() {\n const values = new Array(this.count_);\n let i = 0;\n let entry;\n for (entry = this.newest_; entry; entry = entry.older) {\n values[i++] = entry.value_;\n }\n return values;\n};\n\n\n/**\n * @return {T} Last value.\n */\nLRUCache.prototype.peekLast = function() {\n return this.oldest_.value_;\n};\n\n\n/**\n * @return {string} Last key.\n */\nLRUCache.prototype.peekLastKey = function() {\n return this.oldest_.key_;\n};\n\n\n/**\n * Get the key of the newest item in the cache. Throws if the cache is empty.\n * @return {string} The newest key.\n */\nLRUCache.prototype.peekFirstKey = function() {\n return this.newest_.key_;\n};\n\n\n/**\n * @return {T} value Value.\n */\nLRUCache.prototype.pop = function() {\n const entry = this.oldest_;\n delete this.entries_[entry.key_];\n if (entry.newer) {\n entry.newer.older = null;\n }\n this.oldest_ = /** @type {module:ol/structs/LRUCache~Entry} */ (entry.newer);\n if (!this.oldest_) {\n this.newest_ = null;\n }\n --this.count_;\n return entry.value_;\n};\n\n\n/**\n * @param {string} key Key.\n * @param {T} value Value.\n */\nLRUCache.prototype.replace = function(key, value) {\n this.get(key); // update `newest_`\n this.entries_[key].value_ = value;\n};\n\n\n/**\n * @param {string} key Key.\n * @param {T} value Value.\n */\nLRUCache.prototype.set = function(key, value) {\n assert(!(key in this.entries_),\n 16); // Tried to set a value for a key that is used already\n const entry = /** @type {module:ol/structs/LRUCache~Entry} */ ({\n key_: key,\n newer: null,\n older: this.newest_,\n value_: value\n });\n if (!this.newest_) {\n this.oldest_ = entry;\n } else {\n this.newest_.newer = entry;\n }\n this.newest_ = entry;\n this.entries_[key] = entry;\n ++this.count_;\n};\n\n\n/**\n * Set a maximum number of entries for the cache.\n * @param {number} size Cache size.\n * @api\n */\nLRUCache.prototype.setSize = function(size) {\n this.highWaterMark = size;\n};\n\n\n/**\n * Prune the cache.\n */\nLRUCache.prototype.prune = function() {\n while (this.canExpireCache()) {\n this.pop();\n }\n};\nexport default LRUCache;\n","/**\n * @module ol/render/canvas\n */\nimport {getFontFamilies} from '../css.js';\nimport {createCanvasContext2D} from '../dom.js';\nimport {clear} from '../obj.js';\nimport LRUCache from '../structs/LRUCache.js';\nimport {create as createTransform} from '../transform.js';\n\n\n/**\n * @typedef {Object} FillState\n * @property {module:ol/colorlike~ColorLike} fillStyle\n */\n\n\n/**\n * @typedef {Object} FillStrokeState\n * @property {module:ol/colorlike~ColorLike} [currentFillStyle]\n * @property {module:ol/colorlike~ColorLike} [currentStrokeStyle]\n * @property {string} [currentLineCap]\n * @property {Array.} currentLineDash\n * @property {number} [currentLineDashOffset]\n * @property {string} [currentLineJoin]\n * @property {number} [currentLineWidth]\n * @property {number} [currentMiterLimit]\n * @property {number} [lastStroke]\n * @property {module:ol/colorlike~ColorLike} [fillStyle]\n * @property {module:ol/colorlike~ColorLike} [strokeStyle]\n * @property {string} [lineCap]\n * @property {Array.} lineDash\n * @property {number} [lineDashOffset]\n * @property {string} [lineJoin]\n * @property {number} [lineWidth]\n * @property {number} [miterLimit]\n */\n\n\n/**\n * @typedef {Object} StrokeState\n * @property {string} lineCap\n * @property {Array.} lineDash\n * @property {number} lineDashOffset\n * @property {string} lineJoin\n * @property {number} lineWidth\n * @property {number} miterLimit\n * @property {module:ol/colorlike~ColorLike} strokeStyle\n */\n\n\n/**\n * @typedef {Object} TextState\n * @property {string} font\n * @property {string} [textAlign]\n * @property {string} textBaseline\n */\n\n\n/**\n * Container for decluttered replay instructions that need to be rendered or\n * omitted together, i.e. when styles render both an image and text, or for the\n * characters that form text along lines. The basic elements of this array are\n * `[minX, minY, maxX, maxY, count]`, where the first four entries are the\n * rendered extent of the group in pixel space. `count` is the number of styles\n * in the group, i.e. 2 when an image and a text are grouped, or 1 otherwise.\n * In addition to these four elements, declutter instruction arrays (i.e. the\n * arguments to {@link module:ol/render/canvas~drawImage} are appended to the array.\n * @typedef {Array.<*>} DeclutterGroup\n */\n\n\n/**\n * @const\n * @type {string}\n */\nexport const defaultFont = '10px sans-serif';\n\n\n/**\n * @const\n * @type {module:ol/color~Color}\n */\nexport const defaultFillStyle = [0, 0, 0, 1];\n\n\n/**\n * @const\n * @type {string}\n */\nexport const defaultLineCap = 'round';\n\n\n/**\n * @const\n * @type {Array.}\n */\nexport const defaultLineDash = [];\n\n\n/**\n * @const\n * @type {number}\n */\nexport const defaultLineDashOffset = 0;\n\n\n/**\n * @const\n * @type {string}\n */\nexport const defaultLineJoin = 'round';\n\n\n/**\n * @const\n * @type {number}\n */\nexport const defaultMiterLimit = 10;\n\n\n/**\n * @const\n * @type {module:ol/color~Color}\n */\nexport const defaultStrokeStyle = [0, 0, 0, 1];\n\n\n/**\n * @const\n * @type {string}\n */\nexport const defaultTextAlign = 'center';\n\n\n/**\n * @const\n * @type {string}\n */\nexport const defaultTextBaseline = 'middle';\n\n\n/**\n * @const\n * @type {Array.}\n */\nexport const defaultPadding = [0, 0, 0, 0];\n\n\n/**\n * @const\n * @type {number}\n */\nexport const defaultLineWidth = 1;\n\n\n/**\n * The label cache for text rendering. To change the default cache size of 2048\n * entries, use {@link module:ol/structs/LRUCache#setSize}.\n * @type {module:ol/structs/LRUCache.}\n * @api\n */\nexport const labelCache = new LRUCache();\n\n\n/**\n * @type {!Object.}\n */\nexport const checkedFonts = {};\n\n\n/**\n * @type {CanvasRenderingContext2D}\n */\nlet measureContext = null;\n\n\n/**\n * @type {!Object.}\n */\nexport const textHeights = {};\n\n\n/**\n * Clears the label cache when a font becomes available.\n * @param {string} fontSpec CSS font spec.\n */\nexport const checkFont = (function() {\n const retries = 60;\n const checked = checkedFonts;\n const size = '32px ';\n const referenceFonts = ['monospace', 'serif'];\n const len = referenceFonts.length;\n const text = 'wmytzilWMYTZIL@#/&?$%10\\uF013';\n let interval, referenceWidth;\n\n function isAvailable(font) {\n const context = getMeasureContext();\n let available = true;\n for (let i = 0; i < len; ++i) {\n const referenceFont = referenceFonts[i];\n context.font = size + referenceFont;\n referenceWidth = context.measureText(text).width;\n if (font != referenceFont) {\n context.font = size + font + ',' + referenceFont;\n const width = context.measureText(text).width;\n // If width and referenceWidth are the same, then the fallback was used\n // instead of the font we wanted, so the font is not available.\n available = available && width != referenceWidth;\n }\n }\n return available;\n }\n\n function check() {\n let done = true;\n for (const font in checked) {\n if (checked[font] < retries) {\n if (isAvailable(font)) {\n checked[font] = retries;\n clear(textHeights);\n // Make sure that loaded fonts are picked up by Safari\n measureContext = null;\n labelCache.clear();\n } else {\n ++checked[font];\n done = false;\n }\n }\n }\n if (done) {\n clearInterval(interval);\n interval = undefined;\n }\n }\n\n return function(fontSpec) {\n const fontFamilies = getFontFamilies(fontSpec);\n if (!fontFamilies) {\n return;\n }\n for (let i = 0, ii = fontFamilies.length; i < ii; ++i) {\n const fontFamily = fontFamilies[i];\n if (!(fontFamily in checked)) {\n checked[fontFamily] = retries;\n if (!isAvailable(fontFamily)) {\n checked[fontFamily] = 0;\n if (interval === undefined) {\n interval = setInterval(check, 32);\n }\n }\n }\n }\n };\n})();\n\n\n/**\n * @return {CanvasRenderingContext2D} Measure context.\n */\nfunction getMeasureContext() {\n if (!measureContext) {\n measureContext = createCanvasContext2D(1, 1);\n }\n return measureContext;\n}\n\n\n/**\n * @param {string} font Font to use for measuring.\n * @return {module:ol/size~Size} Measurement.\n */\nexport const measureTextHeight = (function() {\n let span;\n const heights = textHeights;\n return function(font) {\n let height = heights[font];\n if (height == undefined) {\n if (!span) {\n span = document.createElement('span');\n span.textContent = 'M';\n span.style.margin = span.style.padding = '0 !important';\n span.style.position = 'absolute !important';\n span.style.left = '-99999px !important';\n }\n span.style.font = font;\n document.body.appendChild(span);\n height = heights[font] = span.offsetHeight;\n document.body.removeChild(span);\n }\n return height;\n };\n})();\n\n\n/**\n * @param {string} font Font.\n * @param {string} text Text.\n * @return {number} Width.\n */\nexport function measureTextWidth(font, text) {\n const measureContext = getMeasureContext();\n if (font != measureContext.font) {\n measureContext.font = font;\n }\n return measureContext.measureText(text).width;\n}\n\n\n/**\n * @param {CanvasRenderingContext2D} context Context.\n * @param {number} rotation Rotation.\n * @param {number} offsetX X offset.\n * @param {number} offsetY Y offset.\n */\nexport function rotateAtOffset(context, rotation, offsetX, offsetY) {\n if (rotation !== 0) {\n context.translate(offsetX, offsetY);\n context.rotate(rotation);\n context.translate(-offsetX, -offsetY);\n }\n}\n\n\nexport const resetTransform = createTransform();\n\n\n/**\n * @param {CanvasRenderingContext2D} context Context.\n * @param {module:ol/transform~Transform|null} transform Transform.\n * @param {number} opacity Opacity.\n * @param {HTMLImageElement|HTMLCanvasElement|HTMLVideoElement} image Image.\n * @param {number} originX Origin X.\n * @param {number} originY Origin Y.\n * @param {number} w Width.\n * @param {number} h Height.\n * @param {number} x X.\n * @param {number} y Y.\n * @param {number} scale Scale.\n */\nexport function drawImage(context,\n transform, opacity, image, originX, originY, w, h, x, y, scale) {\n let alpha;\n if (opacity != 1) {\n alpha = context.globalAlpha;\n context.globalAlpha = alpha * opacity;\n }\n if (transform) {\n context.setTransform.apply(context, transform);\n }\n\n context.drawImage(image, originX, originY, w, h, x, y, w * scale, h * scale);\n\n if (alpha) {\n context.globalAlpha = alpha;\n }\n if (transform) {\n context.setTransform.apply(context, resetTransform);\n }\n}\n","/**\n * @module ol/style/Image\n */\n\n\n/**\n * @typedef {Object} Options\n * @property {number} opacity\n * @property {boolean} rotateWithView\n * @property {number} rotation\n * @property {number} scale\n * @property {boolean} snapToPixel\n */\n\n\n/**\n * @classdesc\n * A base class used for creating subclasses and not instantiated in\n * apps. Base class for {@link module:ol/style/Icon~Icon}, {@link module:ol/style/Circle~CircleStyle} and\n * {@link module:ol/style/RegularShape~RegularShape}.\n *\n * @constructor\n * @abstract\n * @param {module:ol/style/Image~Options} options Options.\n * @api\n */\nconst ImageStyle = function(options) {\n\n /**\n * @private\n * @type {number}\n */\n this.opacity_ = options.opacity;\n\n /**\n * @private\n * @type {boolean}\n */\n this.rotateWithView_ = options.rotateWithView;\n\n /**\n * @private\n * @type {number}\n */\n this.rotation_ = options.rotation;\n\n /**\n * @private\n * @type {number}\n */\n this.scale_ = options.scale;\n\n /**\n * @private\n * @type {boolean}\n */\n this.snapToPixel_ = options.snapToPixel;\n\n};\n\n\n/**\n * Get the symbolizer opacity.\n * @return {number} Opacity.\n * @api\n */\nImageStyle.prototype.getOpacity = function() {\n return this.opacity_;\n};\n\n\n/**\n * Determine whether the symbolizer rotates with the map.\n * @return {boolean} Rotate with map.\n * @api\n */\nImageStyle.prototype.getRotateWithView = function() {\n return this.rotateWithView_;\n};\n\n\n/**\n * Get the symoblizer rotation.\n * @return {number} Rotation.\n * @api\n */\nImageStyle.prototype.getRotation = function() {\n return this.rotation_;\n};\n\n\n/**\n * Get the symbolizer scale.\n * @return {number} Scale.\n * @api\n */\nImageStyle.prototype.getScale = function() {\n return this.scale_;\n};\n\n\n/**\n * Determine whether the symbolizer should be snapped to a pixel.\n * @return {boolean} The symbolizer should snap to a pixel.\n * @api\n */\nImageStyle.prototype.getSnapToPixel = function() {\n return this.snapToPixel_;\n};\n\n\n/**\n * Get the anchor point in pixels. The anchor determines the center point for the\n * symbolizer.\n * @abstract\n * @return {Array.} Anchor.\n */\nImageStyle.prototype.getAnchor = function() {};\n\n\n/**\n * Get the image element for the symbolizer.\n * @abstract\n * @param {number} pixelRatio Pixel ratio.\n * @return {HTMLCanvasElement|HTMLVideoElement|Image} Image element.\n */\nImageStyle.prototype.getImage = function(pixelRatio) {};\n\n\n/**\n * @abstract\n * @param {number} pixelRatio Pixel ratio.\n * @return {HTMLCanvasElement|HTMLVideoElement|Image} Image element.\n */\nImageStyle.prototype.getHitDetectionImage = function(pixelRatio) {};\n\n\n/**\n * @abstract\n * @return {module:ol/ImageState} Image state.\n */\nImageStyle.prototype.getImageState = function() {};\n\n\n/**\n * @abstract\n * @return {module:ol/size~Size} Image size.\n */\nImageStyle.prototype.getImageSize = function() {};\n\n\n/**\n * @abstract\n * @return {module:ol/size~Size} Size of the hit-detection image.\n */\nImageStyle.prototype.getHitDetectionImageSize = function() {};\n\n\n/**\n * Get the origin of the symbolizer.\n * @abstract\n * @return {Array.} Origin.\n */\nImageStyle.prototype.getOrigin = function() {};\n\n\n/**\n * Get the size of the symbolizer (in pixels).\n * @abstract\n * @return {module:ol/size~Size} Size.\n */\nImageStyle.prototype.getSize = function() {};\n\n\n/**\n * Set the opacity.\n *\n * @param {number} opacity Opacity.\n * @api\n */\nImageStyle.prototype.setOpacity = function(opacity) {\n this.opacity_ = opacity;\n};\n\n\n/**\n * Set whether to rotate the style with the view.\n *\n * @param {boolean} rotateWithView Rotate with map.\n * @api\n */\nImageStyle.prototype.setRotateWithView = function(rotateWithView) {\n this.rotateWithView_ = rotateWithView;\n};\n\n\n/**\n * Set the rotation.\n *\n * @param {number} rotation Rotation.\n * @api\n */\nImageStyle.prototype.setRotation = function(rotation) {\n this.rotation_ = rotation;\n};\n\n\n/**\n * Set the scale.\n *\n * @param {number} scale Scale.\n * @api\n */\nImageStyle.prototype.setScale = function(scale) {\n this.scale_ = scale;\n};\n\n\n/**\n * Set whether to snap the image to the closest pixel.\n *\n * @param {boolean} snapToPixel Snap to pixel?\n * @api\n */\nImageStyle.prototype.setSnapToPixel = function(snapToPixel) {\n this.snapToPixel_ = snapToPixel;\n};\n\n\n/**\n * @abstract\n * @param {function(this: T, module:ol/events/Event)} listener Listener function.\n * @param {T} thisArg Value to use as `this` when executing `listener`.\n * @return {module:ol/events~EventsKey|undefined} Listener key.\n * @template T\n */\nImageStyle.prototype.listenImageChange = function(listener, thisArg) {};\n\n\n/**\n * Load not yet loaded URI.\n * @abstract\n */\nImageStyle.prototype.load = function() {};\n\n\n/**\n * @abstract\n * @param {function(this: T, module:ol/events/Event)} listener Listener function.\n * @param {T} thisArg Value to use as `this` when executing `listener`.\n * @template T\n */\nImageStyle.prototype.unlistenImageChange = function(listener, thisArg) {};\nexport default ImageStyle;\n","/**\n * @module ol/style/RegularShape\n */\nimport {inherits} from '../util.js';\nimport {asColorLike} from '../colorlike.js';\nimport {createCanvasContext2D} from '../dom.js';\nimport {CANVAS_LINE_DASH} from '../has.js';\nimport ImageState from '../ImageState.js';\nimport {defaultStrokeStyle, defaultFillStyle, defaultLineCap, defaultLineWidth, defaultLineJoin, defaultMiterLimit} from '../render/canvas.js';\nimport ImageStyle from '../style/Image.js';\n\n\n/**\n * Specify radius for regular polygons, or radius1 and radius2 for stars.\n * @typedef {Object} Options\n * @property {module:ol/style/Fill} [fill] Fill style.\n * @property {number} points Number of points for stars and regular polygons. In case of a polygon, the number of points\n * is the number of sides.\n * @property {number} [radius] Radius of a regular polygon.\n * @property {number} [radius1] Outer radius of a star.\n * @property {number} [radius2] Inner radius of a star.\n * @property {number} [angle=0] Shape's angle in radians. A value of 0 will have one of the shape's point facing up.\n * @property {boolean} [snapToPixel=true] If `true` integral numbers of pixels are used as the X and Y pixel coordinate\n * when drawing the shape in the output canvas. If `false` fractional numbers may be used. Using `true` allows for\n * \"sharp\" rendering (no blur), while using `false` allows for \"accurate\" rendering. Note that accuracy is important if\n * the shape's position is animated. Without it, the shape may jitter noticeably.\n * @property {module:ol/style/Stroke} [stroke] Stroke style.\n * @property {number} [rotation=0] Rotation in radians (positive rotation clockwise).\n * @property {boolean} [rotateWithView=false] Whether to rotate the shape with the view.\n * @property {module:ol/style/AtlasManager} [atlasManager] The atlas manager to use for this symbol. When\n * using WebGL it is recommended to use an atlas manager to avoid texture switching. If an atlas manager is given, the\n * symbol is added to an atlas. By default no atlas manager is used.\n */\n\n\n/**\n * @typedef {Object} RenderOptions\n * @property {module:ol/colorlike~ColorLike} [strokeStyle]\n * @property {number} strokeWidth\n * @property {number} size\n * @property {string} lineCap\n * @property {Array.} lineDash\n * @property {number} lineDashOffset\n * @property {string} lineJoin\n * @property {number} miterLimit\n */\n\n\n/**\n * @classdesc\n * Set regular shape style for vector features. The resulting shape will be\n * a regular polygon when `radius` is provided, or a star when `radius1` and\n * `radius2` are provided.\n *\n * @constructor\n * @param {module:ol/style/RegularShape~Options} options Options.\n * @extends {module:ol/style/Image}\n * @api\n */\nconst RegularShape = function(options) {\n /**\n * @private\n * @type {Array.}\n */\n this.checksums_ = null;\n\n /**\n * @private\n * @type {HTMLCanvasElement}\n */\n this.canvas_ = null;\n\n /**\n * @private\n * @type {HTMLCanvasElement}\n */\n this.hitDetectionCanvas_ = null;\n\n /**\n * @private\n * @type {module:ol/style/Fill}\n */\n this.fill_ = options.fill !== undefined ? options.fill : null;\n\n /**\n * @private\n * @type {Array.}\n */\n this.origin_ = [0, 0];\n\n /**\n * @private\n * @type {number}\n */\n this.points_ = options.points;\n\n /**\n * @protected\n * @type {number}\n */\n this.radius_ = /** @type {number} */ (options.radius !== undefined ?\n options.radius : options.radius1);\n\n /**\n * @private\n * @type {number|undefined}\n */\n this.radius2_ = options.radius2;\n\n /**\n * @private\n * @type {number}\n */\n this.angle_ = options.angle !== undefined ? options.angle : 0;\n\n /**\n * @private\n * @type {module:ol/style/Stroke}\n */\n this.stroke_ = options.stroke !== undefined ? options.stroke : null;\n\n /**\n * @private\n * @type {Array.}\n */\n this.anchor_ = null;\n\n /**\n * @private\n * @type {module:ol/size~Size}\n */\n this.size_ = null;\n\n /**\n * @private\n * @type {module:ol/size~Size}\n */\n this.imageSize_ = null;\n\n /**\n * @private\n * @type {module:ol/size~Size}\n */\n this.hitDetectionImageSize_ = null;\n\n /**\n * @protected\n * @type {module:ol/style/AtlasManager|undefined}\n */\n this.atlasManager_ = options.atlasManager;\n\n this.render_(this.atlasManager_);\n\n /**\n * @type {boolean}\n */\n const snapToPixel = options.snapToPixel !== undefined ?\n options.snapToPixel : true;\n\n /**\n * @type {boolean}\n */\n const rotateWithView = options.rotateWithView !== undefined ?\n options.rotateWithView : false;\n\n ImageStyle.call(this, {\n opacity: 1,\n rotateWithView: rotateWithView,\n rotation: options.rotation !== undefined ? options.rotation : 0,\n scale: 1,\n snapToPixel: snapToPixel\n });\n};\n\ninherits(RegularShape, ImageStyle);\n\n\n/**\n * Clones the style. If an atlasmanager was provided to the original style it will be used in the cloned style, too.\n * @return {module:ol/style/RegularShape} The cloned style.\n * @api\n */\nRegularShape.prototype.clone = function() {\n const style = new RegularShape({\n fill: this.getFill() ? this.getFill().clone() : undefined,\n points: this.getPoints(),\n radius: this.getRadius(),\n radius2: this.getRadius2(),\n angle: this.getAngle(),\n snapToPixel: this.getSnapToPixel(),\n stroke: this.getStroke() ? this.getStroke().clone() : undefined,\n rotation: this.getRotation(),\n rotateWithView: this.getRotateWithView(),\n atlasManager: this.atlasManager_\n });\n style.setOpacity(this.getOpacity());\n style.setScale(this.getScale());\n return style;\n};\n\n\n/**\n * @inheritDoc\n * @api\n */\nRegularShape.prototype.getAnchor = function() {\n return this.anchor_;\n};\n\n\n/**\n * Get the angle used in generating the shape.\n * @return {number} Shape's rotation in radians.\n * @api\n */\nRegularShape.prototype.getAngle = function() {\n return this.angle_;\n};\n\n\n/**\n * Get the fill style for the shape.\n * @return {module:ol/style/Fill} Fill style.\n * @api\n */\nRegularShape.prototype.getFill = function() {\n return this.fill_;\n};\n\n\n/**\n * @inheritDoc\n */\nRegularShape.prototype.getHitDetectionImage = function(pixelRatio) {\n return this.hitDetectionCanvas_;\n};\n\n\n/**\n * @inheritDoc\n * @api\n */\nRegularShape.prototype.getImage = function(pixelRatio) {\n return this.canvas_;\n};\n\n\n/**\n * @inheritDoc\n */\nRegularShape.prototype.getImageSize = function() {\n return this.imageSize_;\n};\n\n\n/**\n * @inheritDoc\n */\nRegularShape.prototype.getHitDetectionImageSize = function() {\n return this.hitDetectionImageSize_;\n};\n\n\n/**\n * @inheritDoc\n */\nRegularShape.prototype.getImageState = function() {\n return ImageState.LOADED;\n};\n\n\n/**\n * @inheritDoc\n * @api\n */\nRegularShape.prototype.getOrigin = function() {\n return this.origin_;\n};\n\n\n/**\n * Get the number of points for generating the shape.\n * @return {number} Number of points for stars and regular polygons.\n * @api\n */\nRegularShape.prototype.getPoints = function() {\n return this.points_;\n};\n\n\n/**\n * Get the (primary) radius for the shape.\n * @return {number} Radius.\n * @api\n */\nRegularShape.prototype.getRadius = function() {\n return this.radius_;\n};\n\n\n/**\n * Get the secondary radius for the shape.\n * @return {number|undefined} Radius2.\n * @api\n */\nRegularShape.prototype.getRadius2 = function() {\n return this.radius2_;\n};\n\n\n/**\n * @inheritDoc\n * @api\n */\nRegularShape.prototype.getSize = function() {\n return this.size_;\n};\n\n\n/**\n * Get the stroke style for the shape.\n * @return {module:ol/style/Stroke} Stroke style.\n * @api\n */\nRegularShape.prototype.getStroke = function() {\n return this.stroke_;\n};\n\n\n/**\n * @inheritDoc\n */\nRegularShape.prototype.listenImageChange = function(listener, thisArg) {};\n\n\n/**\n * @inheritDoc\n */\nRegularShape.prototype.load = function() {};\n\n\n/**\n * @inheritDoc\n */\nRegularShape.prototype.unlistenImageChange = function(listener, thisArg) {};\n\n\n/**\n * @protected\n * @param {module:ol/style/AtlasManager|undefined} atlasManager An atlas manager.\n */\nRegularShape.prototype.render_ = function(atlasManager) {\n let imageSize;\n let lineCap = '';\n let lineJoin = '';\n let miterLimit = 0;\n let lineDash = null;\n let lineDashOffset = 0;\n let strokeStyle;\n let strokeWidth = 0;\n\n if (this.stroke_) {\n strokeStyle = this.stroke_.getColor();\n if (strokeStyle === null) {\n strokeStyle = defaultStrokeStyle;\n }\n strokeStyle = asColorLike(strokeStyle);\n strokeWidth = this.stroke_.getWidth();\n if (strokeWidth === undefined) {\n strokeWidth = defaultLineWidth;\n }\n lineDash = this.stroke_.getLineDash();\n lineDashOffset = this.stroke_.getLineDashOffset();\n if (!CANVAS_LINE_DASH) {\n lineDash = null;\n lineDashOffset = 0;\n }\n lineJoin = this.stroke_.getLineJoin();\n if (lineJoin === undefined) {\n lineJoin = defaultLineJoin;\n }\n lineCap = this.stroke_.getLineCap();\n if (lineCap === undefined) {\n lineCap = defaultLineCap;\n }\n miterLimit = this.stroke_.getMiterLimit();\n if (miterLimit === undefined) {\n miterLimit = defaultMiterLimit;\n }\n }\n\n let size = 2 * (this.radius_ + strokeWidth) + 1;\n\n /** @type {module:ol/style/RegularShape~RenderOptions} */\n const renderOptions = {\n strokeStyle: strokeStyle,\n strokeWidth: strokeWidth,\n size: size,\n lineCap: lineCap,\n lineDash: lineDash,\n lineDashOffset: lineDashOffset,\n lineJoin: lineJoin,\n miterLimit: miterLimit\n };\n\n if (atlasManager === undefined) {\n // no atlas manager is used, create a new canvas\n const context = createCanvasContext2D(size, size);\n this.canvas_ = context.canvas;\n\n // canvas.width and height are rounded to the closest integer\n size = this.canvas_.width;\n imageSize = size;\n\n this.draw_(renderOptions, context, 0, 0);\n\n this.createHitDetectionCanvas_(renderOptions);\n } else {\n // an atlas manager is used, add the symbol to an atlas\n size = Math.round(size);\n\n const hasCustomHitDetectionImage = !this.fill_;\n let renderHitDetectionCallback;\n if (hasCustomHitDetectionImage) {\n // render the hit-detection image into a separate atlas image\n renderHitDetectionCallback =\n this.drawHitDetectionCanvas_.bind(this, renderOptions);\n }\n\n const id = this.getChecksum();\n const info = atlasManager.add(\n id, size, size, this.draw_.bind(this, renderOptions),\n renderHitDetectionCallback);\n\n this.canvas_ = info.image;\n this.origin_ = [info.offsetX, info.offsetY];\n imageSize = info.image.width;\n\n if (hasCustomHitDetectionImage) {\n this.hitDetectionCanvas_ = info.hitImage;\n this.hitDetectionImageSize_ =\n [info.hitImage.width, info.hitImage.height];\n } else {\n this.hitDetectionCanvas_ = this.canvas_;\n this.hitDetectionImageSize_ = [imageSize, imageSize];\n }\n }\n\n this.anchor_ = [size / 2, size / 2];\n this.size_ = [size, size];\n this.imageSize_ = [imageSize, imageSize];\n};\n\n\n/**\n * @private\n * @param {module:ol/style/RegularShape~RenderOptions} renderOptions Render options.\n * @param {CanvasRenderingContext2D} context The rendering context.\n * @param {number} x The origin for the symbol (x).\n * @param {number} y The origin for the symbol (y).\n */\nRegularShape.prototype.draw_ = function(renderOptions, context, x, y) {\n let i, angle0, radiusC;\n // reset transform\n context.setTransform(1, 0, 0, 1, 0, 0);\n\n // then move to (x, y)\n context.translate(x, y);\n\n context.beginPath();\n\n let points = this.points_;\n if (points === Infinity) {\n context.arc(\n renderOptions.size / 2, renderOptions.size / 2,\n this.radius_, 0, 2 * Math.PI, true);\n } else {\n const radius2 = (this.radius2_ !== undefined) ? this.radius2_\n : this.radius_;\n if (radius2 !== this.radius_) {\n points = 2 * points;\n }\n for (i = 0; i <= points; i++) {\n angle0 = i * 2 * Math.PI / points - Math.PI / 2 + this.angle_;\n radiusC = i % 2 === 0 ? this.radius_ : radius2;\n context.lineTo(renderOptions.size / 2 + radiusC * Math.cos(angle0),\n renderOptions.size / 2 + radiusC * Math.sin(angle0));\n }\n }\n\n\n if (this.fill_) {\n let color = this.fill_.getColor();\n if (color === null) {\n color = defaultFillStyle;\n }\n context.fillStyle = asColorLike(color);\n context.fill();\n }\n if (this.stroke_) {\n context.strokeStyle = renderOptions.strokeStyle;\n context.lineWidth = renderOptions.strokeWidth;\n if (renderOptions.lineDash) {\n context.setLineDash(renderOptions.lineDash);\n context.lineDashOffset = renderOptions.lineDashOffset;\n }\n context.lineCap = renderOptions.lineCap;\n context.lineJoin = renderOptions.lineJoin;\n context.miterLimit = renderOptions.miterLimit;\n context.stroke();\n }\n context.closePath();\n};\n\n\n/**\n * @private\n * @param {module:ol/style/RegularShape~RenderOptions} renderOptions Render options.\n */\nRegularShape.prototype.createHitDetectionCanvas_ = function(renderOptions) {\n this.hitDetectionImageSize_ = [renderOptions.size, renderOptions.size];\n if (this.fill_) {\n this.hitDetectionCanvas_ = this.canvas_;\n return;\n }\n\n // if no fill style is set, create an extra hit-detection image with a\n // default fill style\n const context = createCanvasContext2D(renderOptions.size, renderOptions.size);\n this.hitDetectionCanvas_ = context.canvas;\n\n this.drawHitDetectionCanvas_(renderOptions, context, 0, 0);\n};\n\n\n/**\n * @private\n * @param {module:ol/style/RegularShape~RenderOptions} renderOptions Render options.\n * @param {CanvasRenderingContext2D} context The context.\n * @param {number} x The origin for the symbol (x).\n * @param {number} y The origin for the symbol (y).\n */\nRegularShape.prototype.drawHitDetectionCanvas_ = function(renderOptions, context, x, y) {\n // reset transform\n context.setTransform(1, 0, 0, 1, 0, 0);\n\n // then move to (x, y)\n context.translate(x, y);\n\n context.beginPath();\n\n let points = this.points_;\n if (points === Infinity) {\n context.arc(\n renderOptions.size / 2, renderOptions.size / 2,\n this.radius_, 0, 2 * Math.PI, true);\n } else {\n const radius2 = (this.radius2_ !== undefined) ? this.radius2_\n : this.radius_;\n if (radius2 !== this.radius_) {\n points = 2 * points;\n }\n let i, radiusC, angle0;\n for (i = 0; i <= points; i++) {\n angle0 = i * 2 * Math.PI / points - Math.PI / 2 + this.angle_;\n radiusC = i % 2 === 0 ? this.radius_ : radius2;\n context.lineTo(renderOptions.size / 2 + radiusC * Math.cos(angle0),\n renderOptions.size / 2 + radiusC * Math.sin(angle0));\n }\n }\n\n context.fillStyle = defaultFillStyle;\n context.fill();\n if (this.stroke_) {\n context.strokeStyle = renderOptions.strokeStyle;\n context.lineWidth = renderOptions.strokeWidth;\n if (renderOptions.lineDash) {\n context.setLineDash(renderOptions.lineDash);\n context.lineDashOffset = renderOptions.lineDashOffset;\n }\n context.stroke();\n }\n context.closePath();\n};\n\n\n/**\n * @return {string} The checksum.\n */\nRegularShape.prototype.getChecksum = function() {\n const strokeChecksum = this.stroke_ ?\n this.stroke_.getChecksum() : '-';\n const fillChecksum = this.fill_ ?\n this.fill_.getChecksum() : '-';\n\n const recalculate = !this.checksums_ ||\n (strokeChecksum != this.checksums_[1] ||\n fillChecksum != this.checksums_[2] ||\n this.radius_ != this.checksums_[3] ||\n this.radius2_ != this.checksums_[4] ||\n this.angle_ != this.checksums_[5] ||\n this.points_ != this.checksums_[6]);\n\n if (recalculate) {\n const checksum = 'r' + strokeChecksum + fillChecksum +\n (this.radius_ !== undefined ? this.radius_.toString() : '-') +\n (this.radius2_ !== undefined ? this.radius2_.toString() : '-') +\n (this.angle_ !== undefined ? this.angle_.toString() : '-') +\n (this.points_ !== undefined ? this.points_.toString() : '-');\n this.checksums_ = [checksum, strokeChecksum, fillChecksum,\n this.radius_, this.radius2_, this.angle_, this.points_];\n }\n\n return this.checksums_[0];\n};\nexport default RegularShape;\n","/**\n * @module ol/style/Circle\n */\nimport {inherits} from '../util.js';\nimport RegularShape from '../style/RegularShape.js';\n\n\n/**\n * @typedef {Object} Options\n * @property {module:ol/style/Fill} [fill] Fill style.\n * @property {number} radius Circle radius.\n * @property {boolean} [snapToPixel=true] If `true` integral numbers of pixels are used as the X and Y pixel coordinate\n * when drawing the circle in the output canvas. If `false` fractional numbers may be used. Using `true` allows for\n * \"sharp\" rendering (no blur), while using `false` allows for \"accurate\" rendering. Note that accuracy is important if\n * the circle's position is animated. Without it, the circle may jitter noticeably.\n * @property {module:ol/style/Stroke} [stroke] Stroke style.\n * @property {module:ol/style/AtlasManager} [atlasManager] The atlas manager to use for this circle.\n * When using WebGL it is recommended to use an atlas manager to avoid texture switching. If an atlas manager is given,\n * the circle is added to an atlas. By default no atlas manager is used.\n */\n\n\n/**\n * @classdesc\n * Set circle style for vector features.\n *\n * @constructor\n * @param {module:ol/style/Circle~Options=} opt_options Options.\n * @extends {module:ol/style/RegularShape}\n * @api\n */\nconst CircleStyle = function(opt_options) {\n\n const options = opt_options || {};\n\n RegularShape.call(this, {\n points: Infinity,\n fill: options.fill,\n radius: options.radius,\n snapToPixel: options.snapToPixel,\n stroke: options.stroke,\n atlasManager: options.atlasManager\n });\n\n};\n\ninherits(CircleStyle, RegularShape);\n\n\n/**\n * Clones the style. If an atlasmanager was provided to the original style it will be used in the cloned style, too.\n * @return {module:ol/style/Circle} The cloned style.\n * @override\n * @api\n */\nCircleStyle.prototype.clone = function() {\n const style = new CircleStyle({\n fill: this.getFill() ? this.getFill().clone() : undefined,\n stroke: this.getStroke() ? this.getStroke().clone() : undefined,\n radius: this.getRadius(),\n snapToPixel: this.getSnapToPixel(),\n atlasManager: this.atlasManager_\n });\n style.setOpacity(this.getOpacity());\n style.setScale(this.getScale());\n return style;\n};\n\n\n/**\n * Set the circle radius.\n *\n * @param {number} radius Circle radius.\n * @api\n */\nCircleStyle.prototype.setRadius = function(radius) {\n this.radius_ = radius;\n this.render_(this.atlasManager_);\n};\nexport default CircleStyle;\n","/**\n * @module ol/style/Fill\n */\nimport {getUid} from '../util.js';\nimport {asString} from '../color.js';\n\n\n/**\n * @typedef {Object} Options\n * @property {module:ol/color~Color|module:ol/colorlike~ColorLike} [color] A color, gradient or pattern.\n * See {@link module:ol/color~Color} and {@link module:ol/colorlike~ColorLike} for possible formats.\n * Default null; if null, the Canvas/renderer default black will be used.\n */\n\n\n/**\n * @classdesc\n * Set fill style for vector features.\n *\n * @constructor\n * @param {module:ol/style/Fill~Options=} opt_options Options.\n * @api\n */\nconst Fill = function(opt_options) {\n\n const options = opt_options || {};\n\n /**\n * @private\n * @type {module:ol/color~Color|module:ol/colorlike~ColorLike}\n */\n this.color_ = options.color !== undefined ? options.color : null;\n\n /**\n * @private\n * @type {string|undefined}\n */\n this.checksum_ = undefined;\n};\n\n\n/**\n * Clones the style. The color is not cloned if it is an {@link module:ol/colorlike~ColorLike}.\n * @return {module:ol/style/Fill} The cloned style.\n * @api\n */\nFill.prototype.clone = function() {\n const color = this.getColor();\n return new Fill({\n color: (color && color.slice) ? color.slice() : color || undefined\n });\n};\n\n\n/**\n * Get the fill color.\n * @return {module:ol/color~Color|module:ol/colorlike~ColorLike} Color.\n * @api\n */\nFill.prototype.getColor = function() {\n return this.color_;\n};\n\n\n/**\n * Set the color.\n *\n * @param {module:ol/color~Color|module:ol/colorlike~ColorLike} color Color.\n * @api\n */\nFill.prototype.setColor = function(color) {\n this.color_ = color;\n this.checksum_ = undefined;\n};\n\n\n/**\n * @return {string} The checksum.\n */\nFill.prototype.getChecksum = function() {\n if (this.checksum_ === undefined) {\n if (\n this.color_ instanceof CanvasPattern ||\n this.color_ instanceof CanvasGradient\n ) {\n this.checksum_ = getUid(this.color_).toString();\n } else {\n this.checksum_ = 'f' + (this.color_ ? asString(this.color_) : '-');\n }\n }\n\n return this.checksum_;\n};\nexport default Fill;\n","/**\n * @module ol/style/Stroke\n */\nimport {getUid} from '../util.js';\n\n\n/**\n * @typedef {Object} Options\n * @property {module:ol/color~Color|module:ol/colorlike~ColorLike} [color] A color, gradient or pattern.\n * See {@link module:ol/color~Color} and {@link module:ol/colorlike~ColorLike} for possible formats.\n * Default null; if null, the Canvas/renderer default black will be used.\n * @property {string} [lineCap='round'] Line cap style: `butt`, `round`, or `square`.\n * @property {string} [lineJoin='round'] Line join style: `bevel`, `round`, or `miter`.\n * @property {Array.} [lineDash] Line dash pattern. Default is `undefined` (no dash).\n * Please note that Internet Explorer 10 and lower do not support the `setLineDash` method on\n * the `CanvasRenderingContext2D` and therefore this option will have no visual effect in these browsers.\n * @property {number} [lineDashOffset=0] Line dash offset.\n * @property {number} [miterLimit=10] Miter limit.\n * @property {number} [width] Width.\n */\n\n\n/**\n * @classdesc\n * Set stroke style for vector features.\n * Note that the defaults given are the Canvas defaults, which will be used if\n * option is not defined. The `get` functions return whatever was entered in\n * the options; they will not return the default.\n *\n * @constructor\n * @param {module:ol/style/Stroke~Options=} opt_options Options.\n * @api\n */\nconst Stroke = function(opt_options) {\n\n const options = opt_options || {};\n\n /**\n * @private\n * @type {module:ol/color~Color|module:ol/colorlike~ColorLike}\n */\n this.color_ = options.color !== undefined ? options.color : null;\n\n /**\n * @private\n * @type {string|undefined}\n */\n this.lineCap_ = options.lineCap;\n\n /**\n * @private\n * @type {Array.}\n */\n this.lineDash_ = options.lineDash !== undefined ? options.lineDash : null;\n\n /**\n * @private\n * @type {number|undefined}\n */\n this.lineDashOffset_ = options.lineDashOffset;\n\n /**\n * @private\n * @type {string|undefined}\n */\n this.lineJoin_ = options.lineJoin;\n\n /**\n * @private\n * @type {number|undefined}\n */\n this.miterLimit_ = options.miterLimit;\n\n /**\n * @private\n * @type {number|undefined}\n */\n this.width_ = options.width;\n\n /**\n * @private\n * @type {string|undefined}\n */\n this.checksum_ = undefined;\n};\n\n\n/**\n * Clones the style.\n * @return {module:ol/style/Stroke} The cloned style.\n * @api\n */\nStroke.prototype.clone = function() {\n const color = this.getColor();\n return new Stroke({\n color: (color && color.slice) ? color.slice() : color || undefined,\n lineCap: this.getLineCap(),\n lineDash: this.getLineDash() ? this.getLineDash().slice() : undefined,\n lineDashOffset: this.getLineDashOffset(),\n lineJoin: this.getLineJoin(),\n miterLimit: this.getMiterLimit(),\n width: this.getWidth()\n });\n};\n\n\n/**\n * Get the stroke color.\n * @return {module:ol/color~Color|module:ol/colorlike~ColorLike} Color.\n * @api\n */\nStroke.prototype.getColor = function() {\n return this.color_;\n};\n\n\n/**\n * Get the line cap type for the stroke.\n * @return {string|undefined} Line cap.\n * @api\n */\nStroke.prototype.getLineCap = function() {\n return this.lineCap_;\n};\n\n\n/**\n * Get the line dash style for the stroke.\n * @return {Array.} Line dash.\n * @api\n */\nStroke.prototype.getLineDash = function() {\n return this.lineDash_;\n};\n\n\n/**\n * Get the line dash offset for the stroke.\n * @return {number|undefined} Line dash offset.\n * @api\n */\nStroke.prototype.getLineDashOffset = function() {\n return this.lineDashOffset_;\n};\n\n\n/**\n * Get the line join type for the stroke.\n * @return {string|undefined} Line join.\n * @api\n */\nStroke.prototype.getLineJoin = function() {\n return this.lineJoin_;\n};\n\n\n/**\n * Get the miter limit for the stroke.\n * @return {number|undefined} Miter limit.\n * @api\n */\nStroke.prototype.getMiterLimit = function() {\n return this.miterLimit_;\n};\n\n\n/**\n * Get the stroke width.\n * @return {number|undefined} Width.\n * @api\n */\nStroke.prototype.getWidth = function() {\n return this.width_;\n};\n\n\n/**\n * Set the color.\n *\n * @param {module:ol/color~Color|module:ol/colorlike~ColorLike} color Color.\n * @api\n */\nStroke.prototype.setColor = function(color) {\n this.color_ = color;\n this.checksum_ = undefined;\n};\n\n\n/**\n * Set the line cap.\n *\n * @param {string|undefined} lineCap Line cap.\n * @api\n */\nStroke.prototype.setLineCap = function(lineCap) {\n this.lineCap_ = lineCap;\n this.checksum_ = undefined;\n};\n\n\n/**\n * Set the line dash.\n *\n * Please note that Internet Explorer 10 and lower [do not support][mdn] the\n * `setLineDash` method on the `CanvasRenderingContext2D` and therefore this\n * property will have no visual effect in these browsers.\n *\n * [mdn]: https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/setLineDash#Browser_compatibility\n *\n * @param {Array.} lineDash Line dash.\n * @api\n */\nStroke.prototype.setLineDash = function(lineDash) {\n this.lineDash_ = lineDash;\n this.checksum_ = undefined;\n};\n\n\n/**\n * Set the line dash offset.\n *\n * @param {number|undefined} lineDashOffset Line dash offset.\n * @api\n */\nStroke.prototype.setLineDashOffset = function(lineDashOffset) {\n this.lineDashOffset_ = lineDashOffset;\n this.checksum_ = undefined;\n};\n\n\n/**\n * Set the line join.\n *\n * @param {string|undefined} lineJoin Line join.\n * @api\n */\nStroke.prototype.setLineJoin = function(lineJoin) {\n this.lineJoin_ = lineJoin;\n this.checksum_ = undefined;\n};\n\n\n/**\n * Set the miter limit.\n *\n * @param {number|undefined} miterLimit Miter limit.\n * @api\n */\nStroke.prototype.setMiterLimit = function(miterLimit) {\n this.miterLimit_ = miterLimit;\n this.checksum_ = undefined;\n};\n\n\n/**\n * Set the width.\n *\n * @param {number|undefined} width Width.\n * @api\n */\nStroke.prototype.setWidth = function(width) {\n this.width_ = width;\n this.checksum_ = undefined;\n};\n\n\n/**\n * @return {string} The checksum.\n */\nStroke.prototype.getChecksum = function() {\n if (this.checksum_ === undefined) {\n this.checksum_ = 's';\n if (this.color_) {\n if (typeof this.color_ === 'string') {\n this.checksum_ += this.color_;\n } else {\n this.checksum_ += getUid(this.color_).toString();\n }\n } else {\n this.checksum_ += '-';\n }\n this.checksum_ += ',' +\n (this.lineCap_ !== undefined ?\n this.lineCap_.toString() : '-') + ',' +\n (this.lineDash_ ?\n this.lineDash_.toString() : '-') + ',' +\n (this.lineDashOffset_ !== undefined ?\n this.lineDashOffset_ : '-') + ',' +\n (this.lineJoin_ !== undefined ?\n this.lineJoin_ : '-') + ',' +\n (this.miterLimit_ !== undefined ?\n this.miterLimit_.toString() : '-') + ',' +\n (this.width_ !== undefined ?\n this.width_.toString() : '-');\n }\n\n return this.checksum_;\n};\nexport default Stroke;\n","/**\n * @module ol/style/Style\n */\n\n/**\n * Feature styles.\n *\n * If no style is defined, the following default style is used:\n * ```js\n * import {Fill, Stroke, Circle, Style} from 'ol/style';\n *\n * var fill = new Fill({\n * color: 'rgba(255,255,255,0.4)'\n * });\n * var stroke = new Stroke({\n * color: '#3399CC',\n * width: 1.25\n * });\n * var styles = [\n * new Style({\n * image: new Circle({\n * fill: fill,\n * stroke: stroke,\n * radius: 5\n * }),\n * fill: fill,\n * stroke: stroke\n * })\n * ];\n * ```\n *\n * A separate editing style has the following defaults:\n * ```js\n * import {Fill, Stroke, Circle, Style} from 'ol/style';\n * import GeometryType from 'ol/geom/GeometryType';\n *\n * var white = [255, 255, 255, 1];\n * var blue = [0, 153, 255, 1];\n * var width = 3;\n * styles[GeometryType.POLYGON] = [\n * new Style({\n * fill: new Fill({\n * color: [255, 255, 255, 0.5]\n * })\n * })\n * ];\n * styles[GeometryType.MULTI_POLYGON] =\n * styles[GeometryType.POLYGON];\n * styles[GeometryType.LINE_STRING] = [\n * new Style({\n * stroke: new Stroke({\n * color: white,\n * width: width + 2\n * })\n * }),\n * new Style({\n * stroke: new Stroke({\n * color: blue,\n * width: width\n * })\n * })\n * ];\n * styles[GeometryType.MULTI_LINE_STRING] =\n * styles[GeometryType.LINE_STRING];\n * styles[GeometryType.POINT] = [\n * new Style({\n * image: new Circle({\n * radius: width * 2,\n * fill: new Fill({\n * color: blue\n * }),\n * stroke: new Stroke({\n * color: white,\n * width: width / 2\n * })\n * }),\n * zIndex: Infinity\n * })\n * ];\n * styles[GeometryType.MULTI_POINT] =\n * styles[GeometryType.POINT];\n * styles[GeometryType.GEOMETRY_COLLECTION] =\n * styles[GeometryType.POLYGON].concat(\n * styles[GeometryType.LINE_STRING],\n * styles[GeometryType.POINT]\n * );\n * ```\n */\nimport {assert} from '../asserts.js';\nimport GeometryType from '../geom/GeometryType.js';\nimport CircleStyle from '../style/Circle.js';\nimport Fill from '../style/Fill.js';\nimport Stroke from '../style/Stroke.js';\n\n\n/**\n * A function that takes an {@link module:ol/Feature} and a `{number}`\n * representing the view's resolution. The function should return a\n * {@link module:ol/style/Style} or an array of them. This way e.g. a\n * vector layer can be styled.\n *\n * @typedef {function((module:ol/Feature|module:ol/render/Feature), number):\n * (module:ol/style/Style|Array.)} StyleFunction\n */\n\n\n/**\n * A function that takes an {@link module:ol/Feature} as argument and returns an\n * {@link module:ol/geom/Geometry} that will be rendered and styled for the feature.\n *\n * @typedef {function((module:ol/Feature|module:ol/render/Feature)):\n * (module:ol/geom/Geometry|module:ol/render/Feature|undefined)} GeometryFunction\n */\n\n\n/**\n * Custom renderer function. Takes two arguments:\n *\n * 1. The pixel coordinates of the geometry in GeoJSON notation.\n * 2. The {@link module:ol/render~State} of the layer renderer.\n *\n * @typedef {function((module:ol/coordinate~Coordinate|Array|Array.>),module:ol/render~State)}\n * RenderFunction\n */\n\n\n/**\n * @typedef {Object} Options\n * @property {string|module:ol/geom/Geometry|module:ol/style/Style~GeometryFunction} [geometry] Feature property or geometry\n * or function returning a geometry to render for this style.\n * @property {module:ol/style/Fill} [fill] Fill style.\n * @property {module:ol/style/Image} [image] Image style.\n * @property {module:ol/style/Style~RenderFunction} [renderer] Custom renderer. When configured, `fill`, `stroke` and `image` will be\n * ignored, and the provided function will be called with each render frame for each geometry.\n * @property {module:ol/style/Stroke} [stroke] Stroke style.\n * @property {module:ol/style/Text} [text] Text style.\n * @property {number} [zIndex] Z index.\n */\n\n\n/**\n * @classdesc\n * Container for vector feature rendering styles. Any changes made to the style\n * or its children through `set*()` methods will not take effect until the\n * feature or layer that uses the style is re-rendered.\n *\n * @constructor\n * @struct\n * @param {module:ol/style/Style~Options=} opt_options Style options.\n * @api\n */\nconst Style = function(opt_options) {\n\n const options = opt_options || {};\n\n /**\n * @private\n * @type {string|module:ol/geom/Geometry|module:ol/style/Style~GeometryFunction}\n */\n this.geometry_ = null;\n\n /**\n * @private\n * @type {!module:ol/style/Style~GeometryFunction}\n */\n this.geometryFunction_ = defaultGeometryFunction;\n\n if (options.geometry !== undefined) {\n this.setGeometry(options.geometry);\n }\n\n /**\n * @private\n * @type {module:ol/style/Fill}\n */\n this.fill_ = options.fill !== undefined ? options.fill : null;\n\n /**\n * @private\n * @type {module:ol/style/Image}\n */\n this.image_ = options.image !== undefined ? options.image : null;\n\n /**\n * @private\n * @type {module:ol/style/Style~RenderFunction|null}\n */\n this.renderer_ = options.renderer !== undefined ? options.renderer : null;\n\n /**\n * @private\n * @type {module:ol/style/Stroke}\n */\n this.stroke_ = options.stroke !== undefined ? options.stroke : null;\n\n /**\n * @private\n * @type {module:ol/style/Text}\n */\n this.text_ = options.text !== undefined ? options.text : null;\n\n /**\n * @private\n * @type {number|undefined}\n */\n this.zIndex_ = options.zIndex;\n\n};\n\n\n/**\n * Clones the style.\n * @return {module:ol/style/Style} The cloned style.\n * @api\n */\nStyle.prototype.clone = function() {\n let geometry = this.getGeometry();\n if (geometry && geometry.clone) {\n geometry = geometry.clone();\n }\n return new Style({\n geometry: geometry,\n fill: this.getFill() ? this.getFill().clone() : undefined,\n image: this.getImage() ? this.getImage().clone() : undefined,\n stroke: this.getStroke() ? this.getStroke().clone() : undefined,\n text: this.getText() ? this.getText().clone() : undefined,\n zIndex: this.getZIndex()\n });\n};\n\n\n/**\n * Get the custom renderer function that was configured with\n * {@link #setRenderer} or the `renderer` constructor option.\n * @return {module:ol/style/Style~RenderFunction|null} Custom renderer function.\n * @api\n */\nStyle.prototype.getRenderer = function() {\n return this.renderer_;\n};\n\n\n/**\n * Sets a custom renderer function for this style. When set, `fill`, `stroke`\n * and `image` options of the style will be ignored.\n * @param {module:ol/style/Style~RenderFunction|null} renderer Custom renderer function.\n * @api\n */\nStyle.prototype.setRenderer = function(renderer) {\n this.renderer_ = renderer;\n};\n\n\n/**\n * Get the geometry to be rendered.\n * @return {string|module:ol/geom/Geometry|module:ol/style/Style~GeometryFunction}\n * Feature property or geometry or function that returns the geometry that will\n * be rendered with this style.\n * @api\n */\nStyle.prototype.getGeometry = function() {\n return this.geometry_;\n};\n\n\n/**\n * Get the function used to generate a geometry for rendering.\n * @return {!module:ol/style/Style~GeometryFunction} Function that is called with a feature\n * and returns the geometry to render instead of the feature's geometry.\n * @api\n */\nStyle.prototype.getGeometryFunction = function() {\n return this.geometryFunction_;\n};\n\n\n/**\n * Get the fill style.\n * @return {module:ol/style/Fill} Fill style.\n * @api\n */\nStyle.prototype.getFill = function() {\n return this.fill_;\n};\n\n\n/**\n * Set the fill style.\n * @param {module:ol/style/Fill} fill Fill style.\n * @api\n */\nStyle.prototype.setFill = function(fill) {\n this.fill_ = fill;\n};\n\n\n/**\n * Get the image style.\n * @return {module:ol/style/Image} Image style.\n * @api\n */\nStyle.prototype.getImage = function() {\n return this.image_;\n};\n\n\n/**\n * Set the image style.\n * @param {module:ol/style/Image} image Image style.\n * @api\n */\nStyle.prototype.setImage = function(image) {\n this.image_ = image;\n};\n\n\n/**\n * Get the stroke style.\n * @return {module:ol/style/Stroke} Stroke style.\n * @api\n */\nStyle.prototype.getStroke = function() {\n return this.stroke_;\n};\n\n\n/**\n * Set the stroke style.\n * @param {module:ol/style/Stroke} stroke Stroke style.\n * @api\n */\nStyle.prototype.setStroke = function(stroke) {\n this.stroke_ = stroke;\n};\n\n\n/**\n * Get the text style.\n * @return {module:ol/style/Text} Text style.\n * @api\n */\nStyle.prototype.getText = function() {\n return this.text_;\n};\n\n\n/**\n * Set the text style.\n * @param {module:ol/style/Text} text Text style.\n * @api\n */\nStyle.prototype.setText = function(text) {\n this.text_ = text;\n};\n\n\n/**\n * Get the z-index for the style.\n * @return {number|undefined} ZIndex.\n * @api\n */\nStyle.prototype.getZIndex = function() {\n return this.zIndex_;\n};\n\n\n/**\n * Set a geometry that is rendered instead of the feature's geometry.\n *\n * @param {string|module:ol/geom/Geometry|module:ol/style/Style~GeometryFunction} geometry\n * Feature property or geometry or function returning a geometry to render\n * for this style.\n * @api\n */\nStyle.prototype.setGeometry = function(geometry) {\n if (typeof geometry === 'function') {\n this.geometryFunction_ = geometry;\n } else if (typeof geometry === 'string') {\n this.geometryFunction_ = function(feature) {\n return (\n /** @type {module:ol/geom/Geometry} */ (feature.get(geometry))\n );\n };\n } else if (!geometry) {\n this.geometryFunction_ = defaultGeometryFunction;\n } else if (geometry !== undefined) {\n this.geometryFunction_ = function() {\n return (\n /** @type {module:ol/geom/Geometry} */ (geometry)\n );\n };\n }\n this.geometry_ = geometry;\n};\n\n\n/**\n * Set the z-index.\n *\n * @param {number|undefined} zIndex ZIndex.\n * @api\n */\nStyle.prototype.setZIndex = function(zIndex) {\n this.zIndex_ = zIndex;\n};\n\n\n/**\n * Convert the provided object into a style function. Functions passed through\n * unchanged. Arrays of module:ol/style/Style or single style objects wrapped in a\n * new style function.\n * @param {module:ol/style/Style~StyleFunction|Array.|module:ol/style/Style} obj\n * A style function, a single style, or an array of styles.\n * @return {module:ol/style/Style~StyleFunction} A style function.\n */\nexport function toFunction(obj) {\n let styleFunction;\n\n if (typeof obj === 'function') {\n styleFunction = obj;\n } else {\n /**\n * @type {Array.}\n */\n let styles;\n if (Array.isArray(obj)) {\n styles = obj;\n } else {\n assert(obj instanceof Style,\n 41); // Expected an `module:ol/style/Style~Style` or an array of `module:ol/style/Style~Style`\n styles = [obj];\n }\n styleFunction = function() {\n return styles;\n };\n }\n return styleFunction;\n}\n\n\n/**\n * @type {Array.}\n */\nlet defaultStyles = null;\n\n\n/**\n * @param {module:ol/Feature|module:ol/render/Feature} feature Feature.\n * @param {number} resolution Resolution.\n * @return {Array.} Style.\n */\nexport function createDefaultStyle(feature, resolution) {\n // We don't use an immediately-invoked function\n // and a closure so we don't get an error at script evaluation time in\n // browsers that do not support Canvas. (module:ol/style/Circle~CircleStyle does\n // canvas.getContext('2d') at construction time, which will cause an.error\n // in such browsers.)\n if (!defaultStyles) {\n const fill = new Fill({\n color: 'rgba(255,255,255,0.4)'\n });\n const stroke = new Stroke({\n color: '#3399CC',\n width: 1.25\n });\n defaultStyles = [\n new Style({\n image: new CircleStyle({\n fill: fill,\n stroke: stroke,\n radius: 5\n }),\n fill: fill,\n stroke: stroke\n })\n ];\n }\n return defaultStyles;\n}\n\n\n/**\n * Default styles for editing features.\n * @return {Object.>} Styles\n */\nexport function createEditingStyle() {\n /** @type {Object.>} */\n const styles = {};\n const white = [255, 255, 255, 1];\n const blue = [0, 153, 255, 1];\n const width = 3;\n styles[GeometryType.POLYGON] = [\n new Style({\n fill: new Fill({\n color: [255, 255, 255, 0.5]\n })\n })\n ];\n styles[GeometryType.MULTI_POLYGON] =\n styles[GeometryType.POLYGON];\n\n styles[GeometryType.LINE_STRING] = [\n new Style({\n stroke: new Stroke({\n color: white,\n width: width + 2\n })\n }),\n new Style({\n stroke: new Stroke({\n color: blue,\n width: width\n })\n })\n ];\n styles[GeometryType.MULTI_LINE_STRING] =\n styles[GeometryType.LINE_STRING];\n\n styles[GeometryType.CIRCLE] =\n styles[GeometryType.POLYGON].concat(\n styles[GeometryType.LINE_STRING]\n );\n\n\n styles[GeometryType.POINT] = [\n new Style({\n image: new CircleStyle({\n radius: width * 2,\n fill: new Fill({\n color: blue\n }),\n stroke: new Stroke({\n color: white,\n width: width / 2\n })\n }),\n zIndex: Infinity\n })\n ];\n styles[GeometryType.MULTI_POINT] =\n styles[GeometryType.POINT];\n\n styles[GeometryType.GEOMETRY_COLLECTION] =\n styles[GeometryType.POLYGON].concat(\n styles[GeometryType.LINE_STRING],\n styles[GeometryType.POINT]\n );\n\n return styles;\n}\n\n\n/**\n * Function that is called with a feature and returns its default geometry.\n * @param {module:ol/Feature|module:ol/render/Feature} feature Feature to get the geometry for.\n * @return {module:ol/geom/Geometry|module:ol/render/Feature|undefined} Geometry to render.\n */\nfunction defaultGeometryFunction(feature) {\n return feature.getGeometry();\n}\n\nexport default Style;\n","/**\n * @module ol/Feature\n */\nimport {assert} from './asserts.js';\nimport {listen, unlisten, unlistenByKey} from './events.js';\nimport EventType from './events/EventType.js';\nimport {inherits} from './util.js';\nimport BaseObject, {getChangeEventType} from './Object.js';\nimport Geometry from './geom/Geometry.js';\nimport Style from './style/Style.js';\n\n/**\n * @classdesc\n * A vector object for geographic features with a geometry and other\n * attribute properties, similar to the features in vector file formats like\n * GeoJSON.\n *\n * Features can be styled individually with `setStyle`; otherwise they use the\n * style of their vector layer.\n *\n * Note that attribute properties are set as {@link module:ol/Object} properties on\n * the feature object, so they are observable, and have get/set accessors.\n *\n * Typically, a feature has a single geometry property. You can set the\n * geometry using the `setGeometry` method and get it with `getGeometry`.\n * It is possible to store more than one geometry on a feature using attribute\n * properties. By default, the geometry used for rendering is identified by\n * the property name `geometry`. If you want to use another geometry property\n * for rendering, use the `setGeometryName` method to change the attribute\n * property associated with the geometry for the feature. For example:\n *\n * ```js\n *\n * import Feature from 'ol/Feature';\n * import Polygon from 'ol/geom/Polygon';\n * import Point from 'ol/geom/Point';\n *\n * var feature = new Feature({\n * geometry: new Polygon(polyCoords),\n * labelPoint: new Point(labelCoords),\n * name: 'My Polygon'\n * });\n *\n * // get the polygon geometry\n * var poly = feature.getGeometry();\n *\n * // Render the feature as a point using the coordinates from labelPoint\n * feature.setGeometryName('labelPoint');\n *\n * // get the point geometry\n * var point = feature.getGeometry();\n * ```\n *\n * @constructor\n * @extends {module:ol/Object}\n * @param {module:ol/geom/Geometry|Object.=} opt_geometryOrProperties\n * You may pass a Geometry object directly, or an object literal containing\n * properties. If you pass an object literal, you may include a Geometry\n * associated with a `geometry` key.\n * @api\n */\nconst Feature = function(opt_geometryOrProperties) {\n\n BaseObject.call(this);\n\n /**\n * @private\n * @type {number|string|undefined}\n */\n this.id_ = undefined;\n\n /**\n * @type {string}\n * @private\n */\n this.geometryName_ = 'geometry';\n\n /**\n * User provided style.\n * @private\n * @type {module:ol/style/Style|Array.|module:ol/style/Style~StyleFunction}\n */\n this.style_ = null;\n\n /**\n * @private\n * @type {module:ol/style/Style~StyleFunction|undefined}\n */\n this.styleFunction_ = undefined;\n\n /**\n * @private\n * @type {?module:ol/events~EventsKey}\n */\n this.geometryChangeKey_ = null;\n\n listen(\n this, getChangeEventType(this.geometryName_),\n this.handleGeometryChanged_, this);\n\n if (opt_geometryOrProperties !== undefined) {\n if (opt_geometryOrProperties instanceof Geometry ||\n !opt_geometryOrProperties) {\n const geometry = opt_geometryOrProperties;\n this.setGeometry(geometry);\n } else {\n /** @type {Object.} */\n const properties = opt_geometryOrProperties;\n this.setProperties(properties);\n }\n }\n};\n\ninherits(Feature, BaseObject);\n\n\n/**\n * Clone this feature. If the original feature has a geometry it\n * is also cloned. The feature id is not set in the clone.\n * @return {module:ol/Feature} The clone.\n * @api\n */\nFeature.prototype.clone = function() {\n const clone = new Feature(this.getProperties());\n clone.setGeometryName(this.getGeometryName());\n const geometry = this.getGeometry();\n if (geometry) {\n clone.setGeometry(geometry.clone());\n }\n const style = this.getStyle();\n if (style) {\n clone.setStyle(style);\n }\n return clone;\n};\n\n\n/**\n * Get the feature's default geometry. A feature may have any number of named\n * geometries. The \"default\" geometry (the one that is rendered by default) is\n * set when calling {@link module:ol/Feature~Feature#setGeometry}.\n * @return {module:ol/geom/Geometry|undefined} The default geometry for the feature.\n * @api\n * @observable\n */\nFeature.prototype.getGeometry = function() {\n return (\n /** @type {module:ol/geom/Geometry|undefined} */ (this.get(this.geometryName_))\n );\n};\n\n\n/**\n * Get the feature identifier. This is a stable identifier for the feature and\n * is either set when reading data from a remote source or set explicitly by\n * calling {@link module:ol/Feature~Feature#setId}.\n * @return {number|string|undefined} Id.\n * @api\n */\nFeature.prototype.getId = function() {\n return this.id_;\n};\n\n\n/**\n * Get the name of the feature's default geometry. By default, the default\n * geometry is named `geometry`.\n * @return {string} Get the property name associated with the default geometry\n * for this feature.\n * @api\n */\nFeature.prototype.getGeometryName = function() {\n return this.geometryName_;\n};\n\n\n/**\n * Get the feature's style. Will return what was provided to the\n * {@link module:ol/Feature~Feature#setStyle} method.\n * @return {module:ol/style/Style|Array.|module:ol/style/Style~StyleFunction} The feature style.\n * @api\n */\nFeature.prototype.getStyle = function() {\n return this.style_;\n};\n\n\n/**\n * Get the feature's style function.\n * @return {module:ol/style/Style~StyleFunction|undefined} Return a function\n * representing the current style of this feature.\n * @api\n */\nFeature.prototype.getStyleFunction = function() {\n return this.styleFunction_;\n};\n\n\n/**\n * @private\n */\nFeature.prototype.handleGeometryChange_ = function() {\n this.changed();\n};\n\n\n/**\n * @private\n */\nFeature.prototype.handleGeometryChanged_ = function() {\n if (this.geometryChangeKey_) {\n unlistenByKey(this.geometryChangeKey_);\n this.geometryChangeKey_ = null;\n }\n const geometry = this.getGeometry();\n if (geometry) {\n this.geometryChangeKey_ = listen(geometry,\n EventType.CHANGE, this.handleGeometryChange_, this);\n }\n this.changed();\n};\n\n\n/**\n * Set the default geometry for the feature. This will update the property\n * with the name returned by {@link module:ol/Feature~Feature#getGeometryName}.\n * @param {module:ol/geom/Geometry|undefined} geometry The new geometry.\n * @api\n * @observable\n */\nFeature.prototype.setGeometry = function(geometry) {\n this.set(this.geometryName_, geometry);\n};\n\n\n/**\n * Set the style for the feature. This can be a single style object, an array\n * of styles, or a function that takes a resolution and returns an array of\n * styles. If it is `null` the feature has no style (a `null` style).\n * @param {module:ol/style/Style|Array.|module:ol/style/Style~StyleFunction} style Style for this feature.\n * @api\n * @fires module:ol/events/Event~Event#event:change\n */\nFeature.prototype.setStyle = function(style) {\n this.style_ = style;\n this.styleFunction_ = !style ? undefined : createStyleFunction(style);\n this.changed();\n};\n\n\n/**\n * Set the feature id. The feature id is considered stable and may be used when\n * requesting features or comparing identifiers returned from a remote source.\n * The feature id can be used with the\n * {@link module:ol/source/Vector~VectorSource#getFeatureById} method.\n * @param {number|string|undefined} id The feature id.\n * @api\n * @fires module:ol/events/Event~Event#event:change\n */\nFeature.prototype.setId = function(id) {\n this.id_ = id;\n this.changed();\n};\n\n\n/**\n * Set the property name to be used when getting the feature's default geometry.\n * When calling {@link module:ol/Feature~Feature#getGeometry}, the value of the property with\n * this name will be returned.\n * @param {string} name The property name of the default geometry.\n * @api\n */\nFeature.prototype.setGeometryName = function(name) {\n unlisten(\n this, getChangeEventType(this.geometryName_),\n this.handleGeometryChanged_, this);\n this.geometryName_ = name;\n listen(\n this, getChangeEventType(this.geometryName_),\n this.handleGeometryChanged_, this);\n this.handleGeometryChanged_();\n};\n\n\n/**\n * Convert the provided object into a feature style function. Functions passed\n * through unchanged. Arrays of module:ol/style/Style or single style objects wrapped\n * in a new feature style function.\n * @param {module:ol/style/Style~StyleFunction|!Array.|!module:ol/style/Style} obj\n * A feature style function, a single style, or an array of styles.\n * @return {module:ol/style/Style~StyleFunction} A style function.\n */\nexport function createStyleFunction(obj) {\n if (typeof obj === 'function') {\n return obj;\n } else {\n /**\n * @type {Array.}\n */\n let styles;\n if (Array.isArray(obj)) {\n styles = obj;\n } else {\n assert(obj instanceof Style,\n 41); // Expected an `module:ol/style/Style~Style` or an array of `module:ol/style/Style~Style`\n styles = [obj];\n }\n return function() {\n return styles;\n };\n }\n}\nexport default Feature;\n","/**\n * @module ol/GeolocationProperty\n */\n\n/**\n * @enum {string}\n */\nexport default {\n ACCURACY: 'accuracy',\n ACCURACY_GEOMETRY: 'accuracyGeometry',\n ALTITUDE: 'altitude',\n ALTITUDE_ACCURACY: 'altitudeAccuracy',\n HEADING: 'heading',\n POSITION: 'position',\n PROJECTION: 'projection',\n SPEED: 'speed',\n TRACKING: 'tracking',\n TRACKING_OPTIONS: 'trackingOptions'\n};\n","/**\n * @module ol/array\n */\n\n\n/**\n * Performs a binary search on the provided sorted list and returns the index of the item if found. If it can't be found it'll return -1.\n * https://github.com/darkskyapp/binary-search\n *\n * @param {Array.<*>} haystack Items to search through.\n * @param {*} needle The item to look for.\n * @param {Function=} opt_comparator Comparator function.\n * @return {number} The index of the item if found, -1 if not.\n */\nexport function binarySearch(haystack, needle, opt_comparator) {\n let mid, cmp;\n const comparator = opt_comparator || numberSafeCompareFunction;\n let low = 0;\n let high = haystack.length;\n let found = false;\n\n while (low < high) {\n /* Note that \"(low + high) >>> 1\" may overflow, and results in a typecast\n * to double (which gives the wrong results). */\n mid = low + (high - low >> 1);\n cmp = +comparator(haystack[mid], needle);\n\n if (cmp < 0.0) { /* Too low. */\n low = mid + 1;\n\n } else { /* Key found or too high */\n high = mid;\n found = !cmp;\n }\n }\n\n /* Key not found. */\n return found ? low : ~low;\n}\n\n\n/**\n * Compare function for array sort that is safe for numbers.\n * @param {*} a The first object to be compared.\n * @param {*} b The second object to be compared.\n * @return {number} A negative number, zero, or a positive number as the first\n * argument is less than, equal to, or greater than the second.\n */\nexport function numberSafeCompareFunction(a, b) {\n return a > b ? 1 : a < b ? -1 : 0;\n}\n\n\n/**\n * Whether the array contains the given object.\n * @param {Array.<*>} arr The array to test for the presence of the element.\n * @param {*} obj The object for which to test.\n * @return {boolean} The object is in the array.\n */\nexport function includes(arr, obj) {\n return arr.indexOf(obj) >= 0;\n}\n\n\n/**\n * @param {Array.} arr Array.\n * @param {number} target Target.\n * @param {number} direction 0 means return the nearest, > 0\n * means return the largest nearest, < 0 means return the\n * smallest nearest.\n * @return {number} Index.\n */\nexport function linearFindNearest(arr, target, direction) {\n const n = arr.length;\n if (arr[0] <= target) {\n return 0;\n } else if (target <= arr[n - 1]) {\n return n - 1;\n } else {\n let i;\n if (direction > 0) {\n for (i = 1; i < n; ++i) {\n if (arr[i] < target) {\n return i - 1;\n }\n }\n } else if (direction < 0) {\n for (i = 1; i < n; ++i) {\n if (arr[i] <= target) {\n return i;\n }\n }\n } else {\n for (i = 1; i < n; ++i) {\n if (arr[i] == target) {\n return i;\n } else if (arr[i] < target) {\n if (arr[i - 1] - target < target - arr[i]) {\n return i - 1;\n } else {\n return i;\n }\n }\n }\n }\n return n - 1;\n }\n}\n\n\n/**\n * @param {Array.<*>} arr Array.\n * @param {number} begin Begin index.\n * @param {number} end End index.\n */\nexport function reverseSubArray(arr, begin, end) {\n while (begin < end) {\n const tmp = arr[begin];\n arr[begin] = arr[end];\n arr[end] = tmp;\n ++begin;\n --end;\n }\n}\n\n\n/**\n * @param {Array.} arr The array to modify.\n * @param {!Array.|VALUE} data The elements or arrays of elements to add to arr.\n * @template VALUE\n */\nexport function extend(arr, data) {\n const extension = Array.isArray(data) ? data : [data];\n const length = extension.length;\n for (let i = 0; i < length; i++) {\n arr[arr.length] = extension[i];\n }\n}\n\n\n/**\n * @param {Array.} arr The array to modify.\n * @param {VALUE} obj The element to remove.\n * @template VALUE\n * @return {boolean} If the element was removed.\n */\nexport function remove(arr, obj) {\n const i = arr.indexOf(obj);\n const found = i > -1;\n if (found) {\n arr.splice(i, 1);\n }\n return found;\n}\n\n\n/**\n * @param {Array.} arr The array to search in.\n * @param {function(VALUE, number, ?) : boolean} func The function to compare.\n * @template VALUE\n * @return {VALUE|null} The element found or null.\n */\nexport function find(arr, func) {\n const length = arr.length >>> 0;\n let value;\n\n for (let i = 0; i < length; i++) {\n value = arr[i];\n if (func(value, i, arr)) {\n return value;\n }\n }\n return null;\n}\n\n\n/**\n * @param {Array|Uint8ClampedArray} arr1 The first array to compare.\n * @param {Array|Uint8ClampedArray} arr2 The second array to compare.\n * @return {boolean} Whether the two arrays are equal.\n */\nexport function equals(arr1, arr2) {\n const len1 = arr1.length;\n if (len1 !== arr2.length) {\n return false;\n }\n for (let i = 0; i < len1; i++) {\n if (arr1[i] !== arr2[i]) {\n return false;\n }\n }\n return true;\n}\n\n\n/**\n * @param {Array.<*>} arr The array to sort (modifies original).\n * @param {Function} compareFnc Comparison function.\n */\nexport function stableSort(arr, compareFnc) {\n const length = arr.length;\n const tmp = Array(arr.length);\n let i;\n for (i = 0; i < length; i++) {\n tmp[i] = {index: i, value: arr[i]};\n }\n tmp.sort(function(a, b) {\n return compareFnc(a.value, b.value) || a.index - b.index;\n });\n for (i = 0; i < arr.length; i++) {\n arr[i] = tmp[i].value;\n }\n}\n\n\n/**\n * @param {Array.<*>} arr The array to search in.\n * @param {Function} func Comparison function.\n * @return {number} Return index.\n */\nexport function findIndex(arr, func) {\n let index;\n const found = !arr.every(function(el, idx) {\n index = idx;\n return !func(el, idx, arr);\n });\n return found ? index : -1;\n}\n\n\n/**\n * @param {Array.<*>} arr The array to test.\n * @param {Function=} opt_func Comparison function.\n * @param {boolean=} opt_strict Strictly sorted (default false).\n * @return {boolean} Return index.\n */\nexport function isSorted(arr, opt_func, opt_strict) {\n const compare = opt_func || numberSafeCompareFunction;\n return arr.every(function(currentVal, index) {\n if (index === 0) {\n return true;\n }\n const res = compare(arr[index - 1], currentVal);\n return !(res > 0 || opt_strict && res === 0);\n });\n}\n","/**\n * @module ol/geom/GeometryLayout\n */\n\n/**\n * The coordinate layout for geometries, indicating whether a 3rd or 4th z ('Z')\n * or measure ('M') coordinate is available. Supported values are `'XY'`,\n * `'XYZ'`, `'XYM'`, `'XYZM'`.\n * @enum {string}\n */\nexport default {\n XY: 'XY',\n XYZ: 'XYZ',\n XYM: 'XYM',\n XYZM: 'XYZM'\n};\n","/**\n * @module ol/geom/SimpleGeometry\n */\nimport {inherits} from '../util.js';\nimport {FALSE} from '../functions.js';\nimport {createOrUpdateFromFlatCoordinates, getCenter} from '../extent.js';\nimport Geometry from '../geom/Geometry.js';\nimport GeometryLayout from '../geom/GeometryLayout.js';\nimport {rotate, scale, translate, transform2D} from '../geom/flat/transform.js';\nimport {clear} from '../obj.js';\n\n/**\n * @classdesc\n * Abstract base class; only used for creating subclasses; do not instantiate\n * in apps, as cannot be rendered.\n *\n * @constructor\n * @abstract\n * @extends {module:ol/geom/Geometry}\n * @api\n */\nconst SimpleGeometry = function() {\n\n Geometry.call(this);\n\n /**\n * @protected\n * @type {module:ol/geom/GeometryLayout}\n */\n this.layout = GeometryLayout.XY;\n\n /**\n * @protected\n * @type {number}\n */\n this.stride = 2;\n\n /**\n * @protected\n * @type {Array.}\n */\n this.flatCoordinates = null;\n\n};\n\ninherits(SimpleGeometry, Geometry);\n\n\n/**\n * @param {number} stride Stride.\n * @return {module:ol/geom/GeometryLayout} layout Layout.\n */\nfunction getLayoutForStride(stride) {\n let layout;\n if (stride == 2) {\n layout = GeometryLayout.XY;\n } else if (stride == 3) {\n layout = GeometryLayout.XYZ;\n } else if (stride == 4) {\n layout = GeometryLayout.XYZM;\n }\n return (\n /** @type {module:ol/geom/GeometryLayout} */ (layout)\n );\n}\n\n\n/**\n * @param {module:ol/geom/GeometryLayout} layout Layout.\n * @return {number} Stride.\n */\nexport function getStrideForLayout(layout) {\n let stride;\n if (layout == GeometryLayout.XY) {\n stride = 2;\n } else if (layout == GeometryLayout.XYZ || layout == GeometryLayout.XYM) {\n stride = 3;\n } else if (layout == GeometryLayout.XYZM) {\n stride = 4;\n }\n return /** @type {number} */ (stride);\n}\n\n\n/**\n * @inheritDoc\n */\nSimpleGeometry.prototype.containsXY = FALSE;\n\n\n/**\n * @inheritDoc\n */\nSimpleGeometry.prototype.computeExtent = function(extent) {\n return createOrUpdateFromFlatCoordinates(this.flatCoordinates,\n 0, this.flatCoordinates.length, this.stride, extent);\n};\n\n\n/**\n * @abstract\n * @return {Array} Coordinates.\n */\nSimpleGeometry.prototype.getCoordinates = function() {};\n\n\n/**\n * Return the first coordinate of the geometry.\n * @return {module:ol/coordinate~Coordinate} First coordinate.\n * @api\n */\nSimpleGeometry.prototype.getFirstCoordinate = function() {\n return this.flatCoordinates.slice(0, this.stride);\n};\n\n\n/**\n * @return {Array.} Flat coordinates.\n */\nSimpleGeometry.prototype.getFlatCoordinates = function() {\n return this.flatCoordinates;\n};\n\n\n/**\n * Return the last coordinate of the geometry.\n * @return {module:ol/coordinate~Coordinate} Last point.\n * @api\n */\nSimpleGeometry.prototype.getLastCoordinate = function() {\n return this.flatCoordinates.slice(this.flatCoordinates.length - this.stride);\n};\n\n\n/**\n * Return the {@link module:ol/geom/GeometryLayout~GeometryLayout layout} of the geometry.\n * @return {module:ol/geom/GeometryLayout} Layout.\n * @api\n */\nSimpleGeometry.prototype.getLayout = function() {\n return this.layout;\n};\n\n\n/**\n * @inheritDoc\n */\nSimpleGeometry.prototype.getSimplifiedGeometry = function(squaredTolerance) {\n if (this.simplifiedGeometryRevision != this.getRevision()) {\n clear(this.simplifiedGeometryCache);\n this.simplifiedGeometryMaxMinSquaredTolerance = 0;\n this.simplifiedGeometryRevision = this.getRevision();\n }\n // If squaredTolerance is negative or if we know that simplification will not\n // have any effect then just return this.\n if (squaredTolerance < 0 ||\n (this.simplifiedGeometryMaxMinSquaredTolerance !== 0 &&\n squaredTolerance <= this.simplifiedGeometryMaxMinSquaredTolerance)) {\n return this;\n }\n const key = squaredTolerance.toString();\n if (this.simplifiedGeometryCache.hasOwnProperty(key)) {\n return this.simplifiedGeometryCache[key];\n } else {\n const simplifiedGeometry =\n this.getSimplifiedGeometryInternal(squaredTolerance);\n const simplifiedFlatCoordinates = simplifiedGeometry.getFlatCoordinates();\n if (simplifiedFlatCoordinates.length < this.flatCoordinates.length) {\n this.simplifiedGeometryCache[key] = simplifiedGeometry;\n return simplifiedGeometry;\n } else {\n // Simplification did not actually remove any coordinates. We now know\n // that any calls to getSimplifiedGeometry with a squaredTolerance less\n // than or equal to the current squaredTolerance will also not have any\n // effect. This allows us to short circuit simplification (saving CPU\n // cycles) and prevents the cache of simplified geometries from filling\n // up with useless identical copies of this geometry (saving memory).\n this.simplifiedGeometryMaxMinSquaredTolerance = squaredTolerance;\n return this;\n }\n }\n};\n\n\n/**\n * @param {number} squaredTolerance Squared tolerance.\n * @return {module:ol/geom/SimpleGeometry} Simplified geometry.\n * @protected\n */\nSimpleGeometry.prototype.getSimplifiedGeometryInternal = function(squaredTolerance) {\n return this;\n};\n\n\n/**\n * @return {number} Stride.\n */\nSimpleGeometry.prototype.getStride = function() {\n return this.stride;\n};\n\n\n/**\n * @param {module:ol/geom/GeometryLayout} layout Layout.\n * @param {Array.} flatCoordinates Flat coordinates.\n * @protected\n */\nSimpleGeometry.prototype.setFlatCoordinatesInternal = function(layout, flatCoordinates) {\n this.stride = getStrideForLayout(layout);\n this.layout = layout;\n this.flatCoordinates = flatCoordinates;\n};\n\n\n/**\n * @abstract\n * @param {Array} coordinates Coordinates.\n * @param {module:ol/geom/GeometryLayout=} opt_layout Layout.\n */\nSimpleGeometry.prototype.setCoordinates = function(coordinates, opt_layout) {};\n\n\n/**\n * @param {module:ol/geom/GeometryLayout|undefined} layout Layout.\n * @param {Array} coordinates Coordinates.\n * @param {number} nesting Nesting.\n * @protected\n */\nSimpleGeometry.prototype.setLayout = function(layout, coordinates, nesting) {\n /** @type {number} */\n let stride;\n if (layout) {\n stride = getStrideForLayout(layout);\n } else {\n for (let i = 0; i < nesting; ++i) {\n if (coordinates.length === 0) {\n this.layout = GeometryLayout.XY;\n this.stride = 2;\n return;\n } else {\n coordinates = /** @type {Array} */ (coordinates[0]);\n }\n }\n stride = coordinates.length;\n layout = getLayoutForStride(stride);\n }\n this.layout = layout;\n this.stride = stride;\n};\n\n\n/**\n * @inheritDoc\n * @api\n */\nSimpleGeometry.prototype.applyTransform = function(transformFn) {\n if (this.flatCoordinates) {\n transformFn(this.flatCoordinates, this.flatCoordinates, this.stride);\n this.changed();\n }\n};\n\n\n/**\n * @inheritDoc\n * @api\n */\nSimpleGeometry.prototype.rotate = function(angle, anchor) {\n const flatCoordinates = this.getFlatCoordinates();\n if (flatCoordinates) {\n const stride = this.getStride();\n rotate(\n flatCoordinates, 0, flatCoordinates.length,\n stride, angle, anchor, flatCoordinates);\n this.changed();\n }\n};\n\n\n/**\n * @inheritDoc\n * @api\n */\nSimpleGeometry.prototype.scale = function(sx, opt_sy, opt_anchor) {\n let sy = opt_sy;\n if (sy === undefined) {\n sy = sx;\n }\n let anchor = opt_anchor;\n if (!anchor) {\n anchor = getCenter(this.getExtent());\n }\n const flatCoordinates = this.getFlatCoordinates();\n if (flatCoordinates) {\n const stride = this.getStride();\n scale(\n flatCoordinates, 0, flatCoordinates.length,\n stride, sx, sy, anchor, flatCoordinates);\n this.changed();\n }\n};\n\n\n/**\n * @inheritDoc\n * @api\n */\nSimpleGeometry.prototype.translate = function(deltaX, deltaY) {\n const flatCoordinates = this.getFlatCoordinates();\n if (flatCoordinates) {\n const stride = this.getStride();\n translate(\n flatCoordinates, 0, flatCoordinates.length, stride,\n deltaX, deltaY, flatCoordinates);\n this.changed();\n }\n};\n\n\n/**\n * @param {module:ol/geom/SimpleGeometry} simpleGeometry Simple geometry.\n * @param {module:ol/transform~Transform} transform Transform.\n * @param {Array.=} opt_dest Destination.\n * @return {Array.} Transformed flat coordinates.\n */\nexport function transformGeom2D(simpleGeometry, transform, opt_dest) {\n const flatCoordinates = simpleGeometry.getFlatCoordinates();\n if (!flatCoordinates) {\n return null;\n } else {\n const stride = simpleGeometry.getStride();\n return transform2D(\n flatCoordinates, 0, flatCoordinates.length, stride,\n transform, opt_dest);\n }\n}\n\nexport default SimpleGeometry;\n","/**\n * @module ol/geom/flat/area\n */\n\n\n/**\n * @param {Array.} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {number} end End.\n * @param {number} stride Stride.\n * @return {number} Area.\n */\nexport function linearRing(flatCoordinates, offset, end, stride) {\n let twiceArea = 0;\n let x1 = flatCoordinates[end - stride];\n let y1 = flatCoordinates[end - stride + 1];\n for (; offset < end; offset += stride) {\n const x2 = flatCoordinates[offset];\n const y2 = flatCoordinates[offset + 1];\n twiceArea += y1 * x2 - x1 * y2;\n x1 = x2;\n y1 = y2;\n }\n return twiceArea / 2;\n}\n\n\n/**\n * @param {Array.} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {Array.} ends Ends.\n * @param {number} stride Stride.\n * @return {number} Area.\n */\nexport function linearRings(flatCoordinates, offset, ends, stride) {\n let area = 0;\n for (let i = 0, ii = ends.length; i < ii; ++i) {\n const end = ends[i];\n area += linearRing(flatCoordinates, offset, end, stride);\n offset = end;\n }\n return area;\n}\n\n\n/**\n * @param {Array.} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {Array.>} endss Endss.\n * @param {number} stride Stride.\n * @return {number} Area.\n */\nexport function linearRingss(flatCoordinates, offset, endss, stride) {\n let area = 0;\n for (let i = 0, ii = endss.length; i < ii; ++i) {\n const ends = endss[i];\n area += linearRings(flatCoordinates, offset, ends, stride);\n offset = ends[ends.length - 1];\n }\n return area;\n}\n","/**\n * @module ol/geom/flat/closest\n */\nimport {lerp, squaredDistance as squaredDx} from '../../math.js';\n\n\n/**\n * Returns the point on the 2D line segment flatCoordinates[offset1] to\n * flatCoordinates[offset2] that is closest to the point (x, y). Extra\n * dimensions are linearly interpolated.\n * @param {Array.} flatCoordinates Flat coordinates.\n * @param {number} offset1 Offset 1.\n * @param {number} offset2 Offset 2.\n * @param {number} stride Stride.\n * @param {number} x X.\n * @param {number} y Y.\n * @param {Array.} closestPoint Closest point.\n */\nfunction assignClosest(flatCoordinates, offset1, offset2, stride, x, y, closestPoint) {\n const x1 = flatCoordinates[offset1];\n const y1 = flatCoordinates[offset1 + 1];\n const dx = flatCoordinates[offset2] - x1;\n const dy = flatCoordinates[offset2 + 1] - y1;\n let offset;\n if (dx === 0 && dy === 0) {\n offset = offset1;\n } else {\n const t = ((x - x1) * dx + (y - y1) * dy) / (dx * dx + dy * dy);\n if (t > 1) {\n offset = offset2;\n } else if (t > 0) {\n for (let i = 0; i < stride; ++i) {\n closestPoint[i] = lerp(flatCoordinates[offset1 + i],\n flatCoordinates[offset2 + i], t);\n }\n closestPoint.length = stride;\n return;\n } else {\n offset = offset1;\n }\n }\n for (let i = 0; i < stride; ++i) {\n closestPoint[i] = flatCoordinates[offset + i];\n }\n closestPoint.length = stride;\n}\n\n\n/**\n * Return the squared of the largest distance between any pair of consecutive\n * coordinates.\n * @param {Array.} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {number} end End.\n * @param {number} stride Stride.\n * @param {number} max Max squared delta.\n * @return {number} Max squared delta.\n */\nexport function maxSquaredDelta(flatCoordinates, offset, end, stride, max) {\n let x1 = flatCoordinates[offset];\n let y1 = flatCoordinates[offset + 1];\n for (offset += stride; offset < end; offset += stride) {\n const x2 = flatCoordinates[offset];\n const y2 = flatCoordinates[offset + 1];\n const squaredDelta = squaredDx(x1, y1, x2, y2);\n if (squaredDelta > max) {\n max = squaredDelta;\n }\n x1 = x2;\n y1 = y2;\n }\n return max;\n}\n\n\n/**\n * @param {Array.} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {Array.} ends Ends.\n * @param {number} stride Stride.\n * @param {number} max Max squared delta.\n * @return {number} Max squared delta.\n */\nexport function arrayMaxSquaredDelta(flatCoordinates, offset, ends, stride, max) {\n for (let i = 0, ii = ends.length; i < ii; ++i) {\n const end = ends[i];\n max = maxSquaredDelta(\n flatCoordinates, offset, end, stride, max);\n offset = end;\n }\n return max;\n}\n\n\n/**\n * @param {Array.} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {Array.>} endss Endss.\n * @param {number} stride Stride.\n * @param {number} max Max squared delta.\n * @return {number} Max squared delta.\n */\nexport function multiArrayMaxSquaredDelta(flatCoordinates, offset, endss, stride, max) {\n for (let i = 0, ii = endss.length; i < ii; ++i) {\n const ends = endss[i];\n max = arrayMaxSquaredDelta(\n flatCoordinates, offset, ends, stride, max);\n offset = ends[ends.length - 1];\n }\n return max;\n}\n\n\n/**\n * @param {Array.} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {number} end End.\n * @param {number} stride Stride.\n * @param {number} maxDelta Max delta.\n * @param {boolean} isRing Is ring.\n * @param {number} x X.\n * @param {number} y Y.\n * @param {Array.} closestPoint Closest point.\n * @param {number} minSquaredDistance Minimum squared distance.\n * @param {Array.=} opt_tmpPoint Temporary point object.\n * @return {number} Minimum squared distance.\n */\nexport function assignClosestPoint(flatCoordinates, offset, end,\n stride, maxDelta, isRing, x, y, closestPoint, minSquaredDistance,\n opt_tmpPoint) {\n if (offset == end) {\n return minSquaredDistance;\n }\n let i, squaredDistance;\n if (maxDelta === 0) {\n // All points are identical, so just test the first point.\n squaredDistance = squaredDx(\n x, y, flatCoordinates[offset], flatCoordinates[offset + 1]);\n if (squaredDistance < minSquaredDistance) {\n for (i = 0; i < stride; ++i) {\n closestPoint[i] = flatCoordinates[offset + i];\n }\n closestPoint.length = stride;\n return squaredDistance;\n } else {\n return minSquaredDistance;\n }\n }\n const tmpPoint = opt_tmpPoint ? opt_tmpPoint : [NaN, NaN];\n let index = offset + stride;\n while (index < end) {\n assignClosest(\n flatCoordinates, index - stride, index, stride, x, y, tmpPoint);\n squaredDistance = squaredDx(x, y, tmpPoint[0], tmpPoint[1]);\n if (squaredDistance < minSquaredDistance) {\n minSquaredDistance = squaredDistance;\n for (i = 0; i < stride; ++i) {\n closestPoint[i] = tmpPoint[i];\n }\n closestPoint.length = stride;\n index += stride;\n } else {\n // Skip ahead multiple points, because we know that all the skipped\n // points cannot be any closer than the closest point we have found so\n // far. We know this because we know how close the current point is, how\n // close the closest point we have found so far is, and the maximum\n // distance between consecutive points. For example, if we're currently\n // at distance 10, the best we've found so far is 3, and that the maximum\n // distance between consecutive points is 2, then we'll need to skip at\n // least (10 - 3) / 2 == 3 (rounded down) points to have any chance of\n // finding a closer point. We use Math.max(..., 1) to ensure that we\n // always advance at least one point, to avoid an infinite loop.\n index += stride * Math.max(\n ((Math.sqrt(squaredDistance) -\n Math.sqrt(minSquaredDistance)) / maxDelta) | 0, 1);\n }\n }\n if (isRing) {\n // Check the closing segment.\n assignClosest(\n flatCoordinates, end - stride, offset, stride, x, y, tmpPoint);\n squaredDistance = squaredDx(x, y, tmpPoint[0], tmpPoint[1]);\n if (squaredDistance < minSquaredDistance) {\n minSquaredDistance = squaredDistance;\n for (i = 0; i < stride; ++i) {\n closestPoint[i] = tmpPoint[i];\n }\n closestPoint.length = stride;\n }\n }\n return minSquaredDistance;\n}\n\n\n/**\n * @param {Array.} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {Array.} ends Ends.\n * @param {number} stride Stride.\n * @param {number} maxDelta Max delta.\n * @param {boolean} isRing Is ring.\n * @param {number} x X.\n * @param {number} y Y.\n * @param {Array.} closestPoint Closest point.\n * @param {number} minSquaredDistance Minimum squared distance.\n * @param {Array.=} opt_tmpPoint Temporary point object.\n * @return {number} Minimum squared distance.\n */\nexport function assignClosestArrayPoint(flatCoordinates, offset, ends,\n stride, maxDelta, isRing, x, y, closestPoint, minSquaredDistance,\n opt_tmpPoint) {\n const tmpPoint = opt_tmpPoint ? opt_tmpPoint : [NaN, NaN];\n for (let i = 0, ii = ends.length; i < ii; ++i) {\n const end = ends[i];\n minSquaredDistance = assignClosestPoint(\n flatCoordinates, offset, end, stride,\n maxDelta, isRing, x, y, closestPoint, minSquaredDistance, tmpPoint);\n offset = end;\n }\n return minSquaredDistance;\n}\n\n\n/**\n * @param {Array.} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {Array.>} endss Endss.\n * @param {number} stride Stride.\n * @param {number} maxDelta Max delta.\n * @param {boolean} isRing Is ring.\n * @param {number} x X.\n * @param {number} y Y.\n * @param {Array.} closestPoint Closest point.\n * @param {number} minSquaredDistance Minimum squared distance.\n * @param {Array.=} opt_tmpPoint Temporary point object.\n * @return {number} Minimum squared distance.\n */\nexport function assignClosestMultiArrayPoint(flatCoordinates, offset,\n endss, stride, maxDelta, isRing, x, y, closestPoint, minSquaredDistance,\n opt_tmpPoint) {\n const tmpPoint = opt_tmpPoint ? opt_tmpPoint : [NaN, NaN];\n for (let i = 0, ii = endss.length; i < ii; ++i) {\n const ends = endss[i];\n minSquaredDistance = assignClosestArrayPoint(\n flatCoordinates, offset, ends, stride,\n maxDelta, isRing, x, y, closestPoint, minSquaredDistance, tmpPoint);\n offset = ends[ends.length - 1];\n }\n return minSquaredDistance;\n}\n","/**\n * @module ol/geom/flat/deflate\n */\n\n\n/**\n * @param {Array.} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {module:ol/coordinate~Coordinate} coordinate Coordinate.\n * @param {number} stride Stride.\n * @return {number} offset Offset.\n */\nexport function deflateCoordinate(flatCoordinates, offset, coordinate, stride) {\n for (let i = 0, ii = coordinate.length; i < ii; ++i) {\n flatCoordinates[offset++] = coordinate[i];\n }\n return offset;\n}\n\n\n/**\n * @param {Array.} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {Array.} coordinates Coordinates.\n * @param {number} stride Stride.\n * @return {number} offset Offset.\n */\nexport function deflateCoordinates(flatCoordinates, offset, coordinates, stride) {\n for (let i = 0, ii = coordinates.length; i < ii; ++i) {\n const coordinate = coordinates[i];\n for (let j = 0; j < stride; ++j) {\n flatCoordinates[offset++] = coordinate[j];\n }\n }\n return offset;\n}\n\n\n/**\n * @param {Array.} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {Array.>} coordinatess Coordinatess.\n * @param {number} stride Stride.\n * @param {Array.=} opt_ends Ends.\n * @return {Array.} Ends.\n */\nexport function deflateCoordinatesArray(flatCoordinates, offset, coordinatess, stride, opt_ends) {\n const ends = opt_ends ? opt_ends : [];\n let i = 0;\n for (let j = 0, jj = coordinatess.length; j < jj; ++j) {\n const end = deflateCoordinates(\n flatCoordinates, offset, coordinatess[j], stride);\n ends[i++] = end;\n offset = end;\n }\n ends.length = i;\n return ends;\n}\n\n\n/**\n * @param {Array.} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {Array.>>} coordinatesss Coordinatesss.\n * @param {number} stride Stride.\n * @param {Array.>=} opt_endss Endss.\n * @return {Array.>} Endss.\n */\nexport function deflateMultiCoordinatesArray(flatCoordinates, offset, coordinatesss, stride, opt_endss) {\n const endss = opt_endss ? opt_endss : [];\n let i = 0;\n for (let j = 0, jj = coordinatesss.length; j < jj; ++j) {\n const ends = deflateCoordinatesArray(\n flatCoordinates, offset, coordinatesss[j], stride, endss[i]);\n endss[i++] = ends;\n offset = ends[ends.length - 1];\n }\n endss.length = i;\n return endss;\n}\n","/**\n * @module ol/geom/flat/inflate\n */\n\n\n/**\n * @param {Array.} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {number} end End.\n * @param {number} stride Stride.\n * @param {Array.=} opt_coordinates Coordinates.\n * @return {Array.} Coordinates.\n */\nexport function inflateCoordinates(flatCoordinates, offset, end, stride, opt_coordinates) {\n const coordinates = opt_coordinates !== undefined ? opt_coordinates : [];\n let i = 0;\n for (let j = offset; j < end; j += stride) {\n coordinates[i++] = flatCoordinates.slice(j, j + stride);\n }\n coordinates.length = i;\n return coordinates;\n}\n\n\n/**\n * @param {Array.} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {Array.} ends Ends.\n * @param {number} stride Stride.\n * @param {Array.>=} opt_coordinatess Coordinatess.\n * @return {Array.>} Coordinatess.\n */\nexport function inflateCoordinatesArray(flatCoordinates, offset, ends, stride, opt_coordinatess) {\n const coordinatess = opt_coordinatess !== undefined ? opt_coordinatess : [];\n let i = 0;\n for (let j = 0, jj = ends.length; j < jj; ++j) {\n const end = ends[j];\n coordinatess[i++] = inflateCoordinates(\n flatCoordinates, offset, end, stride, coordinatess[i]);\n offset = end;\n }\n coordinatess.length = i;\n return coordinatess;\n}\n\n\n/**\n * @param {Array.} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {Array.>} endss Endss.\n * @param {number} stride Stride.\n * @param {Array.>>=} opt_coordinatesss\n * Coordinatesss.\n * @return {Array.>>} Coordinatesss.\n */\nexport function inflateMultiCoordinatesArray(flatCoordinates, offset, endss, stride, opt_coordinatesss) {\n const coordinatesss = opt_coordinatesss !== undefined ? opt_coordinatesss : [];\n let i = 0;\n for (let j = 0, jj = endss.length; j < jj; ++j) {\n const ends = endss[j];\n coordinatesss[i++] = inflateCoordinatesArray(\n flatCoordinates, offset, ends, stride, coordinatesss[i]);\n offset = ends[ends.length - 1];\n }\n coordinatesss.length = i;\n return coordinatesss;\n}\n","/**\n * @module ol/geom/flat/simplify\n */\n// Based on simplify-js https://github.com/mourner/simplify-js\n// Copyright (c) 2012, Vladimir Agafonkin\n// All rights reserved.\n//\n// Redistribution and use in source and binary forms, with or without\n// modification, are permitted provided that the following conditions are met:\n//\n// 1. Redistributions of source code must retain the above copyright notice,\n// this list of conditions and the following disclaimer.\n//\n// 2. Redistributions in binary form must reproduce the above copyright\n// notice, this list of conditions and the following disclaimer in the\n// documentation and/or other materials provided with the distribution.\n//\n// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\n// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\n// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\n// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\n// POSSIBILITY OF SUCH DAMAGE.\n\nimport {squaredSegmentDistance, squaredDistance} from '../../math.js';\n\n\n/**\n * @param {Array.} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {number} end End.\n * @param {number} stride Stride.\n * @param {number} squaredTolerance Squared tolerance.\n * @param {boolean} highQuality Highest quality.\n * @param {Array.=} opt_simplifiedFlatCoordinates Simplified flat\n * coordinates.\n * @return {Array.} Simplified line string.\n */\nexport function simplifyLineString(flatCoordinates, offset, end,\n stride, squaredTolerance, highQuality, opt_simplifiedFlatCoordinates) {\n const simplifiedFlatCoordinates = opt_simplifiedFlatCoordinates !== undefined ?\n opt_simplifiedFlatCoordinates : [];\n if (!highQuality) {\n end = radialDistance(flatCoordinates, offset, end,\n stride, squaredTolerance,\n simplifiedFlatCoordinates, 0);\n flatCoordinates = simplifiedFlatCoordinates;\n offset = 0;\n stride = 2;\n }\n simplifiedFlatCoordinates.length = douglasPeucker(\n flatCoordinates, offset, end, stride, squaredTolerance,\n simplifiedFlatCoordinates, 0);\n return simplifiedFlatCoordinates;\n}\n\n\n/**\n * @param {Array.} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {number} end End.\n * @param {number} stride Stride.\n * @param {number} squaredTolerance Squared tolerance.\n * @param {Array.} simplifiedFlatCoordinates Simplified flat\n * coordinates.\n * @param {number} simplifiedOffset Simplified offset.\n * @return {number} Simplified offset.\n */\nexport function douglasPeucker(flatCoordinates, offset, end,\n stride, squaredTolerance, simplifiedFlatCoordinates, simplifiedOffset) {\n const n = (end - offset) / stride;\n if (n < 3) {\n for (; offset < end; offset += stride) {\n simplifiedFlatCoordinates[simplifiedOffset++] =\n flatCoordinates[offset];\n simplifiedFlatCoordinates[simplifiedOffset++] =\n flatCoordinates[offset + 1];\n }\n return simplifiedOffset;\n }\n /** @type {Array.} */\n const markers = new Array(n);\n markers[0] = 1;\n markers[n - 1] = 1;\n /** @type {Array.} */\n const stack = [offset, end - stride];\n let index = 0;\n while (stack.length > 0) {\n const last = stack.pop();\n const first = stack.pop();\n let maxSquaredDistance = 0;\n const x1 = flatCoordinates[first];\n const y1 = flatCoordinates[first + 1];\n const x2 = flatCoordinates[last];\n const y2 = flatCoordinates[last + 1];\n for (let i = first + stride; i < last; i += stride) {\n const x = flatCoordinates[i];\n const y = flatCoordinates[i + 1];\n const squaredDistance = squaredSegmentDistance(\n x, y, x1, y1, x2, y2);\n if (squaredDistance > maxSquaredDistance) {\n index = i;\n maxSquaredDistance = squaredDistance;\n }\n }\n if (maxSquaredDistance > squaredTolerance) {\n markers[(index - offset) / stride] = 1;\n if (first + stride < index) {\n stack.push(first, index);\n }\n if (index + stride < last) {\n stack.push(index, last);\n }\n }\n }\n for (let i = 0; i < n; ++i) {\n if (markers[i]) {\n simplifiedFlatCoordinates[simplifiedOffset++] =\n flatCoordinates[offset + i * stride];\n simplifiedFlatCoordinates[simplifiedOffset++] =\n flatCoordinates[offset + i * stride + 1];\n }\n }\n return simplifiedOffset;\n}\n\n\n/**\n * @param {Array.} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {Array.} ends Ends.\n * @param {number} stride Stride.\n * @param {number} squaredTolerance Squared tolerance.\n * @param {Array.} simplifiedFlatCoordinates Simplified flat\n * coordinates.\n * @param {number} simplifiedOffset Simplified offset.\n * @param {Array.} simplifiedEnds Simplified ends.\n * @return {number} Simplified offset.\n */\nexport function douglasPeuckerArray(flatCoordinates, offset,\n ends, stride, squaredTolerance, simplifiedFlatCoordinates,\n simplifiedOffset, simplifiedEnds) {\n for (let i = 0, ii = ends.length; i < ii; ++i) {\n const end = ends[i];\n simplifiedOffset = douglasPeucker(\n flatCoordinates, offset, end, stride, squaredTolerance,\n simplifiedFlatCoordinates, simplifiedOffset);\n simplifiedEnds.push(simplifiedOffset);\n offset = end;\n }\n return simplifiedOffset;\n}\n\n\n/**\n * @param {Array.} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {Array.>} endss Endss.\n * @param {number} stride Stride.\n * @param {number} squaredTolerance Squared tolerance.\n * @param {Array.} simplifiedFlatCoordinates Simplified flat\n * coordinates.\n * @param {number} simplifiedOffset Simplified offset.\n * @param {Array.>} simplifiedEndss Simplified endss.\n * @return {number} Simplified offset.\n */\nexport function douglasPeuckerMultiArray(\n flatCoordinates, offset, endss, stride, squaredTolerance,\n simplifiedFlatCoordinates, simplifiedOffset, simplifiedEndss) {\n for (let i = 0, ii = endss.length; i < ii; ++i) {\n const ends = endss[i];\n const simplifiedEnds = [];\n simplifiedOffset = douglasPeuckerArray(\n flatCoordinates, offset, ends, stride, squaredTolerance,\n simplifiedFlatCoordinates, simplifiedOffset, simplifiedEnds);\n simplifiedEndss.push(simplifiedEnds);\n offset = ends[ends.length - 1];\n }\n return simplifiedOffset;\n}\n\n\n/**\n * @param {Array.} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {number} end End.\n * @param {number} stride Stride.\n * @param {number} squaredTolerance Squared tolerance.\n * @param {Array.} simplifiedFlatCoordinates Simplified flat\n * coordinates.\n * @param {number} simplifiedOffset Simplified offset.\n * @return {number} Simplified offset.\n */\nexport function radialDistance(flatCoordinates, offset, end,\n stride, squaredTolerance, simplifiedFlatCoordinates, simplifiedOffset) {\n if (end <= offset + stride) {\n // zero or one point, no simplification possible, so copy and return\n for (; offset < end; offset += stride) {\n simplifiedFlatCoordinates[simplifiedOffset++] = flatCoordinates[offset];\n simplifiedFlatCoordinates[simplifiedOffset++] =\n flatCoordinates[offset + 1];\n }\n return simplifiedOffset;\n }\n let x1 = flatCoordinates[offset];\n let y1 = flatCoordinates[offset + 1];\n // copy first point\n simplifiedFlatCoordinates[simplifiedOffset++] = x1;\n simplifiedFlatCoordinates[simplifiedOffset++] = y1;\n let x2 = x1;\n let y2 = y1;\n for (offset += stride; offset < end; offset += stride) {\n x2 = flatCoordinates[offset];\n y2 = flatCoordinates[offset + 1];\n if (squaredDistance(x1, y1, x2, y2) > squaredTolerance) {\n // copy point at offset\n simplifiedFlatCoordinates[simplifiedOffset++] = x2;\n simplifiedFlatCoordinates[simplifiedOffset++] = y2;\n x1 = x2;\n y1 = y2;\n }\n }\n if (x2 != x1 || y2 != y1) {\n // copy last point\n simplifiedFlatCoordinates[simplifiedOffset++] = x2;\n simplifiedFlatCoordinates[simplifiedOffset++] = y2;\n }\n return simplifiedOffset;\n}\n\n\n/**\n * @param {number} value Value.\n * @param {number} tolerance Tolerance.\n * @return {number} Rounded value.\n */\nexport function snap(value, tolerance) {\n return tolerance * Math.round(value / tolerance);\n}\n\n\n/**\n * Simplifies a line string using an algorithm designed by Tim Schaub.\n * Coordinates are snapped to the nearest value in a virtual grid and\n * consecutive duplicate coordinates are discarded. This effectively preserves\n * topology as the simplification of any subsection of a line string is\n * independent of the rest of the line string. This means that, for examples,\n * the common edge between two polygons will be simplified to the same line\n * string independently in both polygons. This implementation uses a single\n * pass over the coordinates and eliminates intermediate collinear points.\n * @param {Array.} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {number} end End.\n * @param {number} stride Stride.\n * @param {number} tolerance Tolerance.\n * @param {Array.} simplifiedFlatCoordinates Simplified flat\n * coordinates.\n * @param {number} simplifiedOffset Simplified offset.\n * @return {number} Simplified offset.\n */\nexport function quantize(flatCoordinates, offset, end, stride,\n tolerance, simplifiedFlatCoordinates, simplifiedOffset) {\n // do nothing if the line is empty\n if (offset == end) {\n return simplifiedOffset;\n }\n // snap the first coordinate (P1)\n let x1 = snap(flatCoordinates[offset], tolerance);\n let y1 = snap(flatCoordinates[offset + 1], tolerance);\n offset += stride;\n // add the first coordinate to the output\n simplifiedFlatCoordinates[simplifiedOffset++] = x1;\n simplifiedFlatCoordinates[simplifiedOffset++] = y1;\n // find the next coordinate that does not snap to the same value as the first\n // coordinate (P2)\n let x2, y2;\n do {\n x2 = snap(flatCoordinates[offset], tolerance);\n y2 = snap(flatCoordinates[offset + 1], tolerance);\n offset += stride;\n if (offset == end) {\n // all coordinates snap to the same value, the line collapses to a point\n // push the last snapped value anyway to ensure that the output contains\n // at least two points\n // FIXME should we really return at least two points anyway?\n simplifiedFlatCoordinates[simplifiedOffset++] = x2;\n simplifiedFlatCoordinates[simplifiedOffset++] = y2;\n return simplifiedOffset;\n }\n } while (x2 == x1 && y2 == y1);\n while (offset < end) {\n // snap the next coordinate (P3)\n const x3 = snap(flatCoordinates[offset], tolerance);\n const y3 = snap(flatCoordinates[offset + 1], tolerance);\n offset += stride;\n // skip P3 if it is equal to P2\n if (x3 == x2 && y3 == y2) {\n continue;\n }\n // calculate the delta between P1 and P2\n const dx1 = x2 - x1;\n const dy1 = y2 - y1;\n // calculate the delta between P3 and P1\n const dx2 = x3 - x1;\n const dy2 = y3 - y1;\n // if P1, P2, and P3 are colinear and P3 is further from P1 than P2 is from\n // P1 in the same direction then P2 is on the straight line between P1 and\n // P3\n if ((dx1 * dy2 == dy1 * dx2) &&\n ((dx1 < 0 && dx2 < dx1) || dx1 == dx2 || (dx1 > 0 && dx2 > dx1)) &&\n ((dy1 < 0 && dy2 < dy1) || dy1 == dy2 || (dy1 > 0 && dy2 > dy1))) {\n // discard P2 and set P2 = P3\n x2 = x3;\n y2 = y3;\n continue;\n }\n // either P1, P2, and P3 are not colinear, or they are colinear but P3 is\n // between P3 and P1 or on the opposite half of the line to P2. add P2,\n // and continue with P1 = P2 and P2 = P3\n simplifiedFlatCoordinates[simplifiedOffset++] = x2;\n simplifiedFlatCoordinates[simplifiedOffset++] = y2;\n x1 = x2;\n y1 = y2;\n x2 = x3;\n y2 = y3;\n }\n // add the last point (P2)\n simplifiedFlatCoordinates[simplifiedOffset++] = x2;\n simplifiedFlatCoordinates[simplifiedOffset++] = y2;\n return simplifiedOffset;\n}\n\n\n/**\n * @param {Array.} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {Array.} ends Ends.\n * @param {number} stride Stride.\n * @param {number} tolerance Tolerance.\n * @param {Array.} simplifiedFlatCoordinates Simplified flat\n * coordinates.\n * @param {number} simplifiedOffset Simplified offset.\n * @param {Array.} simplifiedEnds Simplified ends.\n * @return {number} Simplified offset.\n */\nexport function quantizeArray(\n flatCoordinates, offset, ends, stride,\n tolerance,\n simplifiedFlatCoordinates, simplifiedOffset, simplifiedEnds) {\n for (let i = 0, ii = ends.length; i < ii; ++i) {\n const end = ends[i];\n simplifiedOffset = quantize(\n flatCoordinates, offset, end, stride,\n tolerance,\n simplifiedFlatCoordinates, simplifiedOffset);\n simplifiedEnds.push(simplifiedOffset);\n offset = end;\n }\n return simplifiedOffset;\n}\n\n\n/**\n * @param {Array.} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {Array.>} endss Endss.\n * @param {number} stride Stride.\n * @param {number} tolerance Tolerance.\n * @param {Array.} simplifiedFlatCoordinates Simplified flat\n * coordinates.\n * @param {number} simplifiedOffset Simplified offset.\n * @param {Array.>} simplifiedEndss Simplified endss.\n * @return {number} Simplified offset.\n */\nexport function quantizeMultiArray(\n flatCoordinates, offset, endss, stride,\n tolerance,\n simplifiedFlatCoordinates, simplifiedOffset, simplifiedEndss) {\n for (let i = 0, ii = endss.length; i < ii; ++i) {\n const ends = endss[i];\n const simplifiedEnds = [];\n simplifiedOffset = quantizeArray(\n flatCoordinates, offset, ends, stride,\n tolerance,\n simplifiedFlatCoordinates, simplifiedOffset, simplifiedEnds);\n simplifiedEndss.push(simplifiedEnds);\n offset = ends[ends.length - 1];\n }\n return simplifiedOffset;\n}\n","/**\n * @module ol/geom/LinearRing\n */\nimport {inherits} from '../util.js';\nimport {closestSquaredDistanceXY} from '../extent.js';\nimport GeometryLayout from '../geom/GeometryLayout.js';\nimport GeometryType from '../geom/GeometryType.js';\nimport SimpleGeometry from '../geom/SimpleGeometry.js';\nimport {linearRing as linearRingArea} from '../geom/flat/area.js';\nimport {assignClosestPoint, maxSquaredDelta} from '../geom/flat/closest.js';\nimport {deflateCoordinates} from '../geom/flat/deflate.js';\nimport {inflateCoordinates} from '../geom/flat/inflate.js';\nimport {douglasPeucker} from '../geom/flat/simplify.js';\n\n/**\n * @classdesc\n * Linear ring geometry. Only used as part of polygon; cannot be rendered\n * on its own.\n *\n * @constructor\n * @extends {module:ol/geom/SimpleGeometry}\n * @param {Array.} coordinates Coordinates.\n * @param {module:ol/geom/GeometryLayout=} opt_layout Layout.\n * @api\n */\nconst LinearRing = function(coordinates, opt_layout) {\n\n SimpleGeometry.call(this);\n\n /**\n * @private\n * @type {number}\n */\n this.maxDelta_ = -1;\n\n /**\n * @private\n * @type {number}\n */\n this.maxDeltaRevision_ = -1;\n\n this.setCoordinates(coordinates, opt_layout);\n\n};\n\ninherits(LinearRing, SimpleGeometry);\n\n\n/**\n * Make a complete copy of the geometry.\n * @return {!module:ol/geom/LinearRing} Clone.\n * @override\n * @api\n */\nLinearRing.prototype.clone = function() {\n const linearRing = new LinearRing(null);\n linearRing.setFlatCoordinates(this.layout, this.flatCoordinates.slice());\n return linearRing;\n};\n\n\n/**\n * @inheritDoc\n */\nLinearRing.prototype.closestPointXY = function(x, y, closestPoint, minSquaredDistance) {\n if (minSquaredDistance < closestSquaredDistanceXY(this.getExtent(), x, y)) {\n return minSquaredDistance;\n }\n if (this.maxDeltaRevision_ != this.getRevision()) {\n this.maxDelta_ = Math.sqrt(maxSquaredDelta(\n this.flatCoordinates, 0, this.flatCoordinates.length, this.stride, 0));\n this.maxDeltaRevision_ = this.getRevision();\n }\n return assignClosestPoint(\n this.flatCoordinates, 0, this.flatCoordinates.length, this.stride,\n this.maxDelta_, true, x, y, closestPoint, minSquaredDistance);\n};\n\n\n/**\n * Return the area of the linear ring on projected plane.\n * @return {number} Area (on projected plane).\n * @api\n */\nLinearRing.prototype.getArea = function() {\n return linearRingArea(this.flatCoordinates, 0, this.flatCoordinates.length, this.stride);\n};\n\n\n/**\n * Return the coordinates of the linear ring.\n * @return {Array.} Coordinates.\n * @override\n * @api\n */\nLinearRing.prototype.getCoordinates = function() {\n return inflateCoordinates(\n this.flatCoordinates, 0, this.flatCoordinates.length, this.stride);\n};\n\n\n/**\n * @inheritDoc\n */\nLinearRing.prototype.getSimplifiedGeometryInternal = function(squaredTolerance) {\n const simplifiedFlatCoordinates = [];\n simplifiedFlatCoordinates.length = douglasPeucker(\n this.flatCoordinates, 0, this.flatCoordinates.length, this.stride,\n squaredTolerance, simplifiedFlatCoordinates, 0);\n const simplifiedLinearRing = new LinearRing(null);\n simplifiedLinearRing.setFlatCoordinates(\n GeometryLayout.XY, simplifiedFlatCoordinates);\n return simplifiedLinearRing;\n};\n\n\n/**\n * @inheritDoc\n * @api\n */\nLinearRing.prototype.getType = function() {\n return GeometryType.LINEAR_RING;\n};\n\n\n/**\n * @inheritDoc\n */\nLinearRing.prototype.intersectsExtent = function(extent) {};\n\n\n/**\n * Set the coordinates of the linear ring.\n * @param {Array.} coordinates Coordinates.\n * @param {module:ol/geom/GeometryLayout=} opt_layout Layout.\n * @override\n * @api\n */\nLinearRing.prototype.setCoordinates = function(coordinates, opt_layout) {\n if (!coordinates) {\n this.setFlatCoordinates(GeometryLayout.XY, null);\n } else {\n this.setLayout(opt_layout, coordinates, 1);\n if (!this.flatCoordinates) {\n this.flatCoordinates = [];\n }\n this.flatCoordinates.length = deflateCoordinates(\n this.flatCoordinates, 0, coordinates, this.stride);\n this.changed();\n }\n};\n\n\n/**\n * @param {module:ol/geom/GeometryLayout} layout Layout.\n * @param {Array.} flatCoordinates Flat coordinates.\n */\nLinearRing.prototype.setFlatCoordinates = function(layout, flatCoordinates) {\n this.setFlatCoordinatesInternal(layout, flatCoordinates);\n this.changed();\n};\nexport default LinearRing;\n","/**\n * @module ol/geom/Point\n */\nimport {inherits} from '../util.js';\nimport {createOrUpdateFromCoordinate, containsXY} from '../extent.js';\nimport GeometryLayout from '../geom/GeometryLayout.js';\nimport GeometryType from '../geom/GeometryType.js';\nimport SimpleGeometry from '../geom/SimpleGeometry.js';\nimport {deflateCoordinate} from '../geom/flat/deflate.js';\nimport {squaredDistance as squaredDx} from '../math.js';\n\n/**\n * @classdesc\n * Point geometry.\n *\n * @constructor\n * @extends {module:ol/geom/SimpleGeometry}\n * @param {module:ol/coordinate~Coordinate} coordinates Coordinates.\n * @param {module:ol/geom/GeometryLayout=} opt_layout Layout.\n * @api\n */\nconst Point = function(coordinates, opt_layout) {\n SimpleGeometry.call(this);\n this.setCoordinates(coordinates, opt_layout);\n};\n\ninherits(Point, SimpleGeometry);\n\n\n/**\n * Make a complete copy of the geometry.\n * @return {!module:ol/geom/Point} Clone.\n * @override\n * @api\n */\nPoint.prototype.clone = function() {\n const point = new Point(null);\n point.setFlatCoordinates(this.layout, this.flatCoordinates.slice());\n return point;\n};\n\n\n/**\n * @inheritDoc\n */\nPoint.prototype.closestPointXY = function(x, y, closestPoint, minSquaredDistance) {\n const flatCoordinates = this.flatCoordinates;\n const squaredDistance = squaredDx(x, y, flatCoordinates[0], flatCoordinates[1]);\n if (squaredDistance < minSquaredDistance) {\n const stride = this.stride;\n for (let i = 0; i < stride; ++i) {\n closestPoint[i] = flatCoordinates[i];\n }\n closestPoint.length = stride;\n return squaredDistance;\n } else {\n return minSquaredDistance;\n }\n};\n\n\n/**\n * Return the coordinate of the point.\n * @return {module:ol/coordinate~Coordinate} Coordinates.\n * @override\n * @api\n */\nPoint.prototype.getCoordinates = function() {\n return !this.flatCoordinates ? [] : this.flatCoordinates.slice();\n};\n\n\n/**\n * @inheritDoc\n */\nPoint.prototype.computeExtent = function(extent) {\n return createOrUpdateFromCoordinate(this.flatCoordinates, extent);\n};\n\n\n/**\n * @inheritDoc\n * @api\n */\nPoint.prototype.getType = function() {\n return GeometryType.POINT;\n};\n\n\n/**\n * @inheritDoc\n * @api\n */\nPoint.prototype.intersectsExtent = function(extent) {\n return containsXY(extent, this.flatCoordinates[0], this.flatCoordinates[1]);\n};\n\n\n/**\n * @inheritDoc\n * @api\n */\nPoint.prototype.setCoordinates = function(coordinates, opt_layout) {\n if (!coordinates) {\n this.setFlatCoordinates(GeometryLayout.XY, null);\n } else {\n this.setLayout(opt_layout, coordinates, 0);\n if (!this.flatCoordinates) {\n this.flatCoordinates = [];\n }\n this.flatCoordinates.length = deflateCoordinate(\n this.flatCoordinates, 0, coordinates, this.stride);\n this.changed();\n }\n};\n\n\n/**\n * @param {module:ol/geom/GeometryLayout} layout Layout.\n * @param {Array.} flatCoordinates Flat coordinates.\n */\nPoint.prototype.setFlatCoordinates = function(layout, flatCoordinates) {\n this.setFlatCoordinatesInternal(layout, flatCoordinates);\n this.changed();\n};\nexport default Point;\n","/**\n * @module ol/geom/flat/contains\n */\nimport {forEachCorner} from '../../extent.js';\n\n\n/**\n * @param {Array.} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {number} end End.\n * @param {number} stride Stride.\n * @param {module:ol/extent~Extent} extent Extent.\n * @return {boolean} Contains extent.\n */\nexport function linearRingContainsExtent(flatCoordinates, offset, end, stride, extent) {\n const outside = forEachCorner(extent,\n /**\n * @param {module:ol/coordinate~Coordinate} coordinate Coordinate.\n * @return {boolean} Contains (x, y).\n */\n function(coordinate) {\n return !linearRingContainsXY(flatCoordinates, offset, end, stride, coordinate[0], coordinate[1]);\n });\n return !outside;\n}\n\n\n/**\n * @param {Array.} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {number} end End.\n * @param {number} stride Stride.\n * @param {number} x X.\n * @param {number} y Y.\n * @return {boolean} Contains (x, y).\n */\nexport function linearRingContainsXY(flatCoordinates, offset, end, stride, x, y) {\n // http://geomalgorithms.com/a03-_inclusion.html\n // Copyright 2000 softSurfer, 2012 Dan Sunday\n // This code may be freely used and modified for any purpose\n // providing that this copyright notice is included with it.\n // SoftSurfer makes no warranty for this code, and cannot be held\n // liable for any real or imagined damage resulting from its use.\n // Users of this code must verify correctness for their application.\n let wn = 0;\n let x1 = flatCoordinates[end - stride];\n let y1 = flatCoordinates[end - stride + 1];\n for (; offset < end; offset += stride) {\n const x2 = flatCoordinates[offset];\n const y2 = flatCoordinates[offset + 1];\n if (y1 <= y) {\n if (y2 > y && ((x2 - x1) * (y - y1)) - ((x - x1) * (y2 - y1)) > 0) {\n wn++;\n }\n } else if (y2 <= y && ((x2 - x1) * (y - y1)) - ((x - x1) * (y2 - y1)) < 0) {\n wn--;\n }\n x1 = x2;\n y1 = y2;\n }\n return wn !== 0;\n}\n\n\n/**\n * @param {Array.} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {Array.} ends Ends.\n * @param {number} stride Stride.\n * @param {number} x X.\n * @param {number} y Y.\n * @return {boolean} Contains (x, y).\n */\nexport function linearRingsContainsXY(flatCoordinates, offset, ends, stride, x, y) {\n if (ends.length === 0) {\n return false;\n }\n if (!linearRingContainsXY(flatCoordinates, offset, ends[0], stride, x, y)) {\n return false;\n }\n for (let i = 1, ii = ends.length; i < ii; ++i) {\n if (linearRingContainsXY(flatCoordinates, ends[i - 1], ends[i], stride, x, y)) {\n return false;\n }\n }\n return true;\n}\n\n\n/**\n * @param {Array.} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {Array.>} endss Endss.\n * @param {number} stride Stride.\n * @param {number} x X.\n * @param {number} y Y.\n * @return {boolean} Contains (x, y).\n */\nexport function linearRingssContainsXY(flatCoordinates, offset, endss, stride, x, y) {\n if (endss.length === 0) {\n return false;\n }\n for (let i = 0, ii = endss.length; i < ii; ++i) {\n const ends = endss[i];\n if (linearRingsContainsXY(flatCoordinates, offset, ends, stride, x, y)) {\n return true;\n }\n offset = ends[ends.length - 1];\n }\n return false;\n}\n","/**\n * @module ol/geom/flat/interiorpoint\n */\nimport {numberSafeCompareFunction} from '../../array.js';\nimport {linearRingsContainsXY} from '../flat/contains.js';\n\n\n/**\n * Calculates a point that is likely to lie in the interior of the linear rings.\n * Inspired by JTS's com.vividsolutions.jts.geom.Geometry#getInteriorPoint.\n * @param {Array.} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {Array.} ends Ends.\n * @param {number} stride Stride.\n * @param {Array.} flatCenters Flat centers.\n * @param {number} flatCentersOffset Flat center offset.\n * @param {Array.=} opt_dest Destination.\n * @return {Array.} Destination point as XYM coordinate, where M is the\n * length of the horizontal intersection that the point belongs to.\n */\nexport function getInteriorPointOfArray(flatCoordinates, offset,\n ends, stride, flatCenters, flatCentersOffset, opt_dest) {\n let i, ii, x, x1, x2, y1, y2;\n const y = flatCenters[flatCentersOffset + 1];\n /** @type {Array.} */\n const intersections = [];\n // Calculate intersections with the horizontal line\n for (let r = 0, rr = ends.length; r < rr; ++r) {\n const end = ends[r];\n x1 = flatCoordinates[end - stride];\n y1 = flatCoordinates[end - stride + 1];\n for (i = offset; i < end; i += stride) {\n x2 = flatCoordinates[i];\n y2 = flatCoordinates[i + 1];\n if ((y <= y1 && y2 <= y) || (y1 <= y && y <= y2)) {\n x = (y - y1) / (y2 - y1) * (x2 - x1) + x1;\n intersections.push(x);\n }\n x1 = x2;\n y1 = y2;\n }\n }\n // Find the longest segment of the horizontal line that has its center point\n // inside the linear ring.\n let pointX = NaN;\n let maxSegmentLength = -Infinity;\n intersections.sort(numberSafeCompareFunction);\n x1 = intersections[0];\n for (i = 1, ii = intersections.length; i < ii; ++i) {\n x2 = intersections[i];\n const segmentLength = Math.abs(x2 - x1);\n if (segmentLength > maxSegmentLength) {\n x = (x1 + x2) / 2;\n if (linearRingsContainsXY(flatCoordinates, offset, ends, stride, x, y)) {\n pointX = x;\n maxSegmentLength = segmentLength;\n }\n }\n x1 = x2;\n }\n if (isNaN(pointX)) {\n // There is no horizontal line that has its center point inside the linear\n // ring. Use the center of the the linear ring's extent.\n pointX = flatCenters[flatCentersOffset];\n }\n if (opt_dest) {\n opt_dest.push(pointX, y, maxSegmentLength);\n return opt_dest;\n } else {\n return [pointX, y, maxSegmentLength];\n }\n}\n\n\n/**\n * @param {Array.} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {Array.>} endss Endss.\n * @param {number} stride Stride.\n * @param {Array.} flatCenters Flat centers.\n * @return {Array.} Interior points as XYM coordinates, where M is the\n * length of the horizontal intersection that the point belongs to.\n */\nexport function getInteriorPointsOfMultiArray(flatCoordinates, offset, endss, stride, flatCenters) {\n let interiorPoints = [];\n for (let i = 0, ii = endss.length; i < ii; ++i) {\n const ends = endss[i];\n interiorPoints = getInteriorPointOfArray(flatCoordinates,\n offset, ends, stride, flatCenters, 2 * i, interiorPoints);\n offset = ends[ends.length - 1];\n }\n return interiorPoints;\n}\n","/**\n * @module ol/geom/flat/segments\n */\n\n\n/**\n * This function calls `callback` for each segment of the flat coordinates\n * array. If the callback returns a truthy value the function returns that\n * value immediately. Otherwise the function returns `false`.\n * @param {Array.} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {number} end End.\n * @param {number} stride Stride.\n * @param {function(this: S, module:ol/coordinate~Coordinate, module:ol/coordinate~Coordinate): T} callback Function\n * called for each segment.\n * @param {S=} opt_this The object to be used as the value of 'this'\n * within callback.\n * @return {T|boolean} Value.\n * @template T,S\n */\nexport function forEach(flatCoordinates, offset, end, stride, callback, opt_this) {\n const point1 = [flatCoordinates[offset], flatCoordinates[offset + 1]];\n const point2 = [];\n let ret;\n for (; (offset + stride) < end; offset += stride) {\n point2[0] = flatCoordinates[offset + stride];\n point2[1] = flatCoordinates[offset + stride + 1];\n ret = callback.call(opt_this, point1, point2);\n if (ret) {\n return ret;\n }\n point1[0] = point2[0];\n point1[1] = point2[1];\n }\n return false;\n}\n","/**\n * @module ol/geom/flat/intersectsextent\n */\nimport {containsExtent, createEmpty, extendFlatCoordinates, intersects, intersectsSegment} from '../../extent.js';\nimport {linearRingContainsXY, linearRingContainsExtent} from '../flat/contains.js';\nimport {forEach as forEachSegment} from '../flat/segments.js';\n\n\n/**\n * @param {Array.} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {number} end End.\n * @param {number} stride Stride.\n * @param {module:ol/extent~Extent} extent Extent.\n * @return {boolean} True if the geometry and the extent intersect.\n */\nexport function intersectsLineString(flatCoordinates, offset, end, stride, extent) {\n const coordinatesExtent = extendFlatCoordinates(\n createEmpty(), flatCoordinates, offset, end, stride);\n if (!intersects(extent, coordinatesExtent)) {\n return false;\n }\n if (containsExtent(extent, coordinatesExtent)) {\n return true;\n }\n if (coordinatesExtent[0] >= extent[0] &&\n coordinatesExtent[2] <= extent[2]) {\n return true;\n }\n if (coordinatesExtent[1] >= extent[1] &&\n coordinatesExtent[3] <= extent[3]) {\n return true;\n }\n return forEachSegment(flatCoordinates, offset, end, stride,\n /**\n * @param {module:ol/coordinate~Coordinate} point1 Start point.\n * @param {module:ol/coordinate~Coordinate} point2 End point.\n * @return {boolean} `true` if the segment and the extent intersect,\n * `false` otherwise.\n */\n function(point1, point2) {\n return intersectsSegment(extent, point1, point2);\n });\n}\n\n\n/**\n * @param {Array.} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {Array.} ends Ends.\n * @param {number} stride Stride.\n * @param {module:ol/extent~Extent} extent Extent.\n * @return {boolean} True if the geometry and the extent intersect.\n */\nexport function intersectsLineStringArray(flatCoordinates, offset, ends, stride, extent) {\n for (let i = 0, ii = ends.length; i < ii; ++i) {\n if (intersectsLineString(\n flatCoordinates, offset, ends[i], stride, extent)) {\n return true;\n }\n offset = ends[i];\n }\n return false;\n}\n\n\n/**\n * @param {Array.} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {number} end End.\n * @param {number} stride Stride.\n * @param {module:ol/extent~Extent} extent Extent.\n * @return {boolean} True if the geometry and the extent intersect.\n */\nexport function intersectsLinearRing(flatCoordinates, offset, end, stride, extent) {\n if (intersectsLineString(\n flatCoordinates, offset, end, stride, extent)) {\n return true;\n }\n if (linearRingContainsXY(flatCoordinates, offset, end, stride, extent[0], extent[1])) {\n return true;\n }\n if (linearRingContainsXY(flatCoordinates, offset, end, stride, extent[0], extent[3])) {\n return true;\n }\n if (linearRingContainsXY(flatCoordinates, offset, end, stride, extent[2], extent[1])) {\n return true;\n }\n if (linearRingContainsXY(flatCoordinates, offset, end, stride, extent[2], extent[3])) {\n return true;\n }\n return false;\n}\n\n\n/**\n * @param {Array.} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {Array.} ends Ends.\n * @param {number} stride Stride.\n * @param {module:ol/extent~Extent} extent Extent.\n * @return {boolean} True if the geometry and the extent intersect.\n */\nexport function intersectsLinearRingArray(flatCoordinates, offset, ends, stride, extent) {\n if (!intersectsLinearRing(\n flatCoordinates, offset, ends[0], stride, extent)) {\n return false;\n }\n if (ends.length === 1) {\n return true;\n }\n for (let i = 1, ii = ends.length; i < ii; ++i) {\n if (linearRingContainsExtent(flatCoordinates, ends[i - 1], ends[i], stride, extent)) {\n return false;\n }\n }\n return true;\n}\n\n\n/**\n * @param {Array.} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {Array.>} endss Endss.\n * @param {number} stride Stride.\n * @param {module:ol/extent~Extent} extent Extent.\n * @return {boolean} True if the geometry and the extent intersect.\n */\nexport function intersectsLinearRingMultiArray(flatCoordinates, offset, endss, stride, extent) {\n for (let i = 0, ii = endss.length; i < ii; ++i) {\n const ends = endss[i];\n if (intersectsLinearRingArray(\n flatCoordinates, offset, ends, stride, extent)) {\n return true;\n }\n offset = ends[ends.length - 1];\n }\n return false;\n}\n","/**\n * @module ol/geom/flat/reverse\n */\n\n\n/**\n * @param {Array.} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {number} end End.\n * @param {number} stride Stride.\n */\nexport function coordinates(flatCoordinates, offset, end, stride) {\n while (offset < end - stride) {\n for (let i = 0; i < stride; ++i) {\n const tmp = flatCoordinates[offset + i];\n flatCoordinates[offset + i] = flatCoordinates[end - stride + i];\n flatCoordinates[end - stride + i] = tmp;\n }\n offset += stride;\n end -= stride;\n }\n}\n","/**\n * @module ol/geom/flat/orient\n */\nimport {coordinates as reverseCoordinates} from '../flat/reverse.js';\n\n\n/**\n * @param {Array.} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {number} end End.\n * @param {number} stride Stride.\n * @return {boolean} Is clockwise.\n */\nexport function linearRingIsClockwise(flatCoordinates, offset, end, stride) {\n // http://tinyurl.com/clockwise-method\n // https://github.com/OSGeo/gdal/blob/trunk/gdal/ogr/ogrlinearring.cpp\n let edge = 0;\n let x1 = flatCoordinates[end - stride];\n let y1 = flatCoordinates[end - stride + 1];\n for (; offset < end; offset += stride) {\n const x2 = flatCoordinates[offset];\n const y2 = flatCoordinates[offset + 1];\n edge += (x2 - x1) * (y2 + y1);\n x1 = x2;\n y1 = y2;\n }\n return edge > 0;\n}\n\n\n/**\n * Determines if linear rings are oriented. By default, left-hand orientation\n * is tested (first ring must be clockwise, remaining rings counter-clockwise).\n * To test for right-hand orientation, use the `opt_right` argument.\n *\n * @param {Array.} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {Array.} ends Array of end indexes.\n * @param {number} stride Stride.\n * @param {boolean=} opt_right Test for right-hand orientation\n * (counter-clockwise exterior ring and clockwise interior rings).\n * @return {boolean} Rings are correctly oriented.\n */\nexport function linearRingIsOriented(flatCoordinates, offset, ends, stride, opt_right) {\n const right = opt_right !== undefined ? opt_right : false;\n for (let i = 0, ii = ends.length; i < ii; ++i) {\n const end = ends[i];\n const isClockwise = linearRingIsClockwise(\n flatCoordinates, offset, end, stride);\n if (i === 0) {\n if ((right && isClockwise) || (!right && !isClockwise)) {\n return false;\n }\n } else {\n if ((right && !isClockwise) || (!right && isClockwise)) {\n return false;\n }\n }\n offset = end;\n }\n return true;\n}\n\n\n/**\n * Determines if linear rings are oriented. By default, left-hand orientation\n * is tested (first ring must be clockwise, remaining rings counter-clockwise).\n * To test for right-hand orientation, use the `opt_right` argument.\n *\n * @param {Array.} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {Array.>} endss Array of array of end indexes.\n * @param {number} stride Stride.\n * @param {boolean=} opt_right Test for right-hand orientation\n * (counter-clockwise exterior ring and clockwise interior rings).\n * @return {boolean} Rings are correctly oriented.\n */\nexport function linearRingsAreOriented(flatCoordinates, offset, endss, stride, opt_right) {\n for (let i = 0, ii = endss.length; i < ii; ++i) {\n if (!linearRingIsOriented(\n flatCoordinates, offset, endss[i], stride, opt_right)) {\n return false;\n }\n }\n return true;\n}\n\n\n/**\n * Orient coordinates in a flat array of linear rings. By default, rings\n * are oriented following the left-hand rule (clockwise for exterior and\n * counter-clockwise for interior rings). To orient according to the\n * right-hand rule, use the `opt_right` argument.\n *\n * @param {Array.} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {Array.} ends Ends.\n * @param {number} stride Stride.\n * @param {boolean=} opt_right Follow the right-hand rule for orientation.\n * @return {number} End.\n */\nexport function orientLinearRings(flatCoordinates, offset, ends, stride, opt_right) {\n const right = opt_right !== undefined ? opt_right : false;\n for (let i = 0, ii = ends.length; i < ii; ++i) {\n const end = ends[i];\n const isClockwise = linearRingIsClockwise(\n flatCoordinates, offset, end, stride);\n const reverse = i === 0 ?\n (right && isClockwise) || (!right && !isClockwise) :\n (right && !isClockwise) || (!right && isClockwise);\n if (reverse) {\n reverseCoordinates(flatCoordinates, offset, end, stride);\n }\n offset = end;\n }\n return offset;\n}\n\n\n/**\n * Orient coordinates in a flat array of linear rings. By default, rings\n * are oriented following the left-hand rule (clockwise for exterior and\n * counter-clockwise for interior rings). To orient according to the\n * right-hand rule, use the `opt_right` argument.\n *\n * @param {Array.} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {Array.>} endss Array of array of end indexes.\n * @param {number} stride Stride.\n * @param {boolean=} opt_right Follow the right-hand rule for orientation.\n * @return {number} End.\n */\nexport function orientLinearRingsArray(flatCoordinates, offset, endss, stride, opt_right) {\n for (let i = 0, ii = endss.length; i < ii; ++i) {\n offset = orientLinearRings(\n flatCoordinates, offset, endss[i], stride, opt_right);\n }\n return offset;\n}\n","/**\n * @module ol/geom/Polygon\n */\nimport {inherits} from '../util.js';\nimport {extend} from '../array.js';\nimport {closestSquaredDistanceXY, getCenter} from '../extent.js';\nimport GeometryLayout from '../geom/GeometryLayout.js';\nimport GeometryType from '../geom/GeometryType.js';\nimport LinearRing from '../geom/LinearRing.js';\nimport Point from '../geom/Point.js';\nimport SimpleGeometry from '../geom/SimpleGeometry.js';\nimport {offset as sphereOffset} from '../sphere.js';\nimport {linearRings as linearRingsArea} from '../geom/flat/area.js';\nimport {assignClosestArrayPoint, arrayMaxSquaredDelta} from '../geom/flat/closest.js';\nimport {linearRingsContainsXY} from '../geom/flat/contains.js';\nimport {deflateCoordinatesArray} from '../geom/flat/deflate.js';\nimport {inflateCoordinatesArray} from '../geom/flat/inflate.js';\nimport {getInteriorPointOfArray} from '../geom/flat/interiorpoint.js';\nimport {intersectsLinearRingArray} from '../geom/flat/intersectsextent.js';\nimport {linearRingIsOriented, orientLinearRings} from '../geom/flat/orient.js';\nimport {quantizeArray} from '../geom/flat/simplify.js';\nimport {modulo} from '../math.js';\n\n/**\n * @classdesc\n * Polygon geometry.\n *\n * @constructor\n * @extends {module:ol/geom/SimpleGeometry}\n * @param {Array.>} coordinates Array of linear\n * rings that define the polygon. The first linear ring of the array\n * defines the outer-boundary or surface of the polygon. Each subsequent\n * linear ring defines a hole in the surface of the polygon. A linear ring\n * is an array of vertices' coordinates where the first coordinate and the\n * last are equivalent.\n * @param {module:ol/geom/GeometryLayout=} opt_layout Layout.\n * @api\n */\nconst Polygon = function(coordinates, opt_layout) {\n\n SimpleGeometry.call(this);\n\n /**\n * @type {Array.}\n * @private\n */\n this.ends_ = [];\n\n /**\n * @private\n * @type {number}\n */\n this.flatInteriorPointRevision_ = -1;\n\n /**\n * @private\n * @type {module:ol/coordinate~Coordinate}\n */\n this.flatInteriorPoint_ = null;\n\n /**\n * @private\n * @type {number}\n */\n this.maxDelta_ = -1;\n\n /**\n * @private\n * @type {number}\n */\n this.maxDeltaRevision_ = -1;\n\n /**\n * @private\n * @type {number}\n */\n this.orientedRevision_ = -1;\n\n /**\n * @private\n * @type {Array.}\n */\n this.orientedFlatCoordinates_ = null;\n\n this.setCoordinates(coordinates, opt_layout);\n\n};\n\ninherits(Polygon, SimpleGeometry);\n\n\n/**\n * Append the passed linear ring to this polygon.\n * @param {module:ol/geom/LinearRing} linearRing Linear ring.\n * @api\n */\nPolygon.prototype.appendLinearRing = function(linearRing) {\n if (!this.flatCoordinates) {\n this.flatCoordinates = linearRing.getFlatCoordinates().slice();\n } else {\n extend(this.flatCoordinates, linearRing.getFlatCoordinates());\n }\n this.ends_.push(this.flatCoordinates.length);\n this.changed();\n};\n\n\n/**\n * Make a complete copy of the geometry.\n * @return {!module:ol/geom/Polygon} Clone.\n * @override\n * @api\n */\nPolygon.prototype.clone = function() {\n const polygon = new Polygon(null);\n polygon.setFlatCoordinates(\n this.layout, this.flatCoordinates.slice(), this.ends_.slice());\n return polygon;\n};\n\n\n/**\n * @inheritDoc\n */\nPolygon.prototype.closestPointXY = function(x, y, closestPoint, minSquaredDistance) {\n if (minSquaredDistance < closestSquaredDistanceXY(this.getExtent(), x, y)) {\n return minSquaredDistance;\n }\n if (this.maxDeltaRevision_ != this.getRevision()) {\n this.maxDelta_ = Math.sqrt(arrayMaxSquaredDelta(\n this.flatCoordinates, 0, this.ends_, this.stride, 0));\n this.maxDeltaRevision_ = this.getRevision();\n }\n return assignClosestArrayPoint(\n this.flatCoordinates, 0, this.ends_, this.stride,\n this.maxDelta_, true, x, y, closestPoint, minSquaredDistance);\n};\n\n\n/**\n * @inheritDoc\n */\nPolygon.prototype.containsXY = function(x, y) {\n return linearRingsContainsXY(this.getOrientedFlatCoordinates(), 0, this.ends_, this.stride, x, y);\n};\n\n\n/**\n * Return the area of the polygon on projected plane.\n * @return {number} Area (on projected plane).\n * @api\n */\nPolygon.prototype.getArea = function() {\n return linearRingsArea(this.getOrientedFlatCoordinates(), 0, this.ends_, this.stride);\n};\n\n\n/**\n * Get the coordinate array for this geometry. This array has the structure\n * of a GeoJSON coordinate array for polygons.\n *\n * @param {boolean=} opt_right Orient coordinates according to the right-hand\n * rule (counter-clockwise for exterior and clockwise for interior rings).\n * If `false`, coordinates will be oriented according to the left-hand rule\n * (clockwise for exterior and counter-clockwise for interior rings).\n * By default, coordinate orientation will depend on how the geometry was\n * constructed.\n * @return {Array.>} Coordinates.\n * @override\n * @api\n */\nPolygon.prototype.getCoordinates = function(opt_right) {\n let flatCoordinates;\n if (opt_right !== undefined) {\n flatCoordinates = this.getOrientedFlatCoordinates().slice();\n orientLinearRings(\n flatCoordinates, 0, this.ends_, this.stride, opt_right);\n } else {\n flatCoordinates = this.flatCoordinates;\n }\n\n return inflateCoordinatesArray(\n flatCoordinates, 0, this.ends_, this.stride);\n};\n\n\n/**\n * @return {Array.} Ends.\n */\nPolygon.prototype.getEnds = function() {\n return this.ends_;\n};\n\n\n/**\n * @return {Array.} Interior point.\n */\nPolygon.prototype.getFlatInteriorPoint = function() {\n if (this.flatInteriorPointRevision_ != this.getRevision()) {\n const flatCenter = getCenter(this.getExtent());\n this.flatInteriorPoint_ = getInteriorPointOfArray(\n this.getOrientedFlatCoordinates(), 0, this.ends_, this.stride,\n flatCenter, 0);\n this.flatInteriorPointRevision_ = this.getRevision();\n }\n return this.flatInteriorPoint_;\n};\n\n\n/**\n * Return an interior point of the polygon.\n * @return {module:ol/geom/Point} Interior point as XYM coordinate, where M is the\n * length of the horizontal intersection that the point belongs to.\n * @api\n */\nPolygon.prototype.getInteriorPoint = function() {\n return new Point(this.getFlatInteriorPoint(), GeometryLayout.XYM);\n};\n\n\n/**\n * Return the number of rings of the polygon, this includes the exterior\n * ring and any interior rings.\n *\n * @return {number} Number of rings.\n * @api\n */\nPolygon.prototype.getLinearRingCount = function() {\n return this.ends_.length;\n};\n\n\n/**\n * Return the Nth linear ring of the polygon geometry. Return `null` if the\n * given index is out of range.\n * The exterior linear ring is available at index `0` and the interior rings\n * at index `1` and beyond.\n *\n * @param {number} index Index.\n * @return {module:ol/geom/LinearRing} Linear ring.\n * @api\n */\nPolygon.prototype.getLinearRing = function(index) {\n if (index < 0 || this.ends_.length <= index) {\n return null;\n }\n const linearRing = new LinearRing(null);\n linearRing.setFlatCoordinates(this.layout, this.flatCoordinates.slice(\n index === 0 ? 0 : this.ends_[index - 1], this.ends_[index]));\n return linearRing;\n};\n\n\n/**\n * Return the linear rings of the polygon.\n * @return {Array.} Linear rings.\n * @api\n */\nPolygon.prototype.getLinearRings = function() {\n const layout = this.layout;\n const flatCoordinates = this.flatCoordinates;\n const ends = this.ends_;\n const linearRings = [];\n let offset = 0;\n for (let i = 0, ii = ends.length; i < ii; ++i) {\n const end = ends[i];\n const linearRing = new LinearRing(null);\n linearRing.setFlatCoordinates(layout, flatCoordinates.slice(offset, end));\n linearRings.push(linearRing);\n offset = end;\n }\n return linearRings;\n};\n\n\n/**\n * @return {Array.} Oriented flat coordinates.\n */\nPolygon.prototype.getOrientedFlatCoordinates = function() {\n if (this.orientedRevision_ != this.getRevision()) {\n const flatCoordinates = this.flatCoordinates;\n if (linearRingIsOriented(\n flatCoordinates, 0, this.ends_, this.stride)) {\n this.orientedFlatCoordinates_ = flatCoordinates;\n } else {\n this.orientedFlatCoordinates_ = flatCoordinates.slice();\n this.orientedFlatCoordinates_.length =\n orientLinearRings(\n this.orientedFlatCoordinates_, 0, this.ends_, this.stride);\n }\n this.orientedRevision_ = this.getRevision();\n }\n return this.orientedFlatCoordinates_;\n};\n\n\n/**\n * @inheritDoc\n */\nPolygon.prototype.getSimplifiedGeometryInternal = function(squaredTolerance) {\n const simplifiedFlatCoordinates = [];\n const simplifiedEnds = [];\n simplifiedFlatCoordinates.length = quantizeArray(\n this.flatCoordinates, 0, this.ends_, this.stride,\n Math.sqrt(squaredTolerance),\n simplifiedFlatCoordinates, 0, simplifiedEnds);\n const simplifiedPolygon = new Polygon(null);\n simplifiedPolygon.setFlatCoordinates(\n GeometryLayout.XY, simplifiedFlatCoordinates, simplifiedEnds);\n return simplifiedPolygon;\n};\n\n\n/**\n * @inheritDoc\n * @api\n */\nPolygon.prototype.getType = function() {\n return GeometryType.POLYGON;\n};\n\n\n/**\n * @inheritDoc\n * @api\n */\nPolygon.prototype.intersectsExtent = function(extent) {\n return intersectsLinearRingArray(\n this.getOrientedFlatCoordinates(), 0, this.ends_, this.stride, extent);\n};\n\n\n/**\n * Set the coordinates of the polygon.\n * @param {Array.>} coordinates Coordinates.\n * @param {module:ol/geom/GeometryLayout=} opt_layout Layout.\n * @override\n * @api\n */\nPolygon.prototype.setCoordinates = function(coordinates, opt_layout) {\n if (!coordinates) {\n this.setFlatCoordinates(GeometryLayout.XY, null, this.ends_);\n } else {\n this.setLayout(opt_layout, coordinates, 2);\n if (!this.flatCoordinates) {\n this.flatCoordinates = [];\n }\n const ends = deflateCoordinatesArray(\n this.flatCoordinates, 0, coordinates, this.stride, this.ends_);\n this.flatCoordinates.length = ends.length === 0 ? 0 : ends[ends.length - 1];\n this.changed();\n }\n};\n\n\n/**\n * @param {module:ol/geom/GeometryLayout} layout Layout.\n * @param {Array.} flatCoordinates Flat coordinates.\n * @param {Array.} ends Ends.\n */\nPolygon.prototype.setFlatCoordinates = function(layout, flatCoordinates, ends) {\n this.setFlatCoordinatesInternal(layout, flatCoordinates);\n this.ends_ = ends;\n this.changed();\n};\n\nexport default Polygon;\n\n\n/**\n * Create an approximation of a circle on the surface of a sphere.\n * @param {module:ol/coordinate~Coordinate} center Center (`[lon, lat]` in degrees).\n * @param {number} radius The great-circle distance from the center to\n * the polygon vertices.\n * @param {number=} opt_n Optional number of vertices for the resulting\n * polygon. Default is `32`.\n * @param {number=} opt_sphereRadius Optional radius for the sphere (defaults to\n * the Earth's mean radius using the WGS84 ellipsoid).\n * @return {module:ol/geom/Polygon} The \"circular\" polygon.\n * @api\n */\nexport function circular(center, radius, opt_n, opt_sphereRadius) {\n const n = opt_n ? opt_n : 32;\n /** @type {Array.} */\n const flatCoordinates = [];\n for (let i = 0; i < n; ++i) {\n extend(flatCoordinates, sphereOffset(center, radius, 2 * Math.PI * i / n, opt_sphereRadius));\n }\n flatCoordinates.push(flatCoordinates[0], flatCoordinates[1]);\n const polygon = new Polygon(null);\n polygon.setFlatCoordinates(GeometryLayout.XY, flatCoordinates, [flatCoordinates.length]);\n return polygon;\n}\n\n\n/**\n * Create a polygon from an extent. The layout used is `XY`.\n * @param {module:ol/extent~Extent} extent The extent.\n * @return {module:ol/geom/Polygon} The polygon.\n * @api\n */\nexport function fromExtent(extent) {\n const minX = extent[0];\n const minY = extent[1];\n const maxX = extent[2];\n const maxY = extent[3];\n const flatCoordinates =\n [minX, minY, minX, maxY, maxX, maxY, maxX, minY, minX, minY];\n const polygon = new Polygon(null);\n polygon.setFlatCoordinates(\n GeometryLayout.XY, flatCoordinates, [flatCoordinates.length]);\n return polygon;\n}\n\n\n/**\n * Create a regular polygon from a circle.\n * @param {module:ol/geom/Circle} circle Circle geometry.\n * @param {number=} opt_sides Number of sides of the polygon. Default is 32.\n * @param {number=} opt_angle Start angle for the first vertex of the polygon in\n * radians. Default is 0.\n * @return {module:ol/geom/Polygon} Polygon geometry.\n * @api\n */\nexport function fromCircle(circle, opt_sides, opt_angle) {\n const sides = opt_sides ? opt_sides : 32;\n const stride = circle.getStride();\n const layout = circle.getLayout();\n const polygon = new Polygon(null, layout);\n const arrayLength = stride * (sides + 1);\n const flatCoordinates = new Array(arrayLength);\n for (let i = 0; i < arrayLength; i++) {\n flatCoordinates[i] = 0;\n }\n const ends = [flatCoordinates.length];\n polygon.setFlatCoordinates(layout, flatCoordinates, ends);\n makeRegular(polygon, circle.getCenter(), circle.getRadius(), opt_angle);\n return polygon;\n}\n\n\n/**\n * Modify the coordinates of a polygon to make it a regular polygon.\n * @param {module:ol/geom/Polygon} polygon Polygon geometry.\n * @param {module:ol/coordinate~Coordinate} center Center of the regular polygon.\n * @param {number} radius Radius of the regular polygon.\n * @param {number=} opt_angle Start angle for the first vertex of the polygon in\n * radians. Default is 0.\n */\nexport function makeRegular(polygon, center, radius, opt_angle) {\n const flatCoordinates = polygon.getFlatCoordinates();\n const layout = polygon.getLayout();\n const stride = polygon.getStride();\n const ends = polygon.getEnds();\n const sides = flatCoordinates.length / stride - 1;\n const startAngle = opt_angle ? opt_angle : 0;\n for (let i = 0; i <= sides; ++i) {\n const offset = i * stride;\n const angle = startAngle + (modulo(i, sides) * 2 * Math.PI / sides);\n flatCoordinates[offset] = center[0] + (radius * Math.cos(angle));\n flatCoordinates[offset + 1] = center[1] + (radius * Math.sin(angle));\n }\n polygon.setFlatCoordinates(layout, flatCoordinates, ends);\n}\n","/**\n * @module ol/Geolocation\n */\nimport {inherits} from './util.js';\nimport GeolocationProperty from './GeolocationProperty.js';\nimport BaseObject, {getChangeEventType} from './Object.js';\nimport {listen} from './events.js';\nimport EventType from './events/EventType.js';\nimport {circular as circularPolygon} from './geom/Polygon.js';\nimport {GEOLOCATION} from './has.js';\nimport {toRadians} from './math.js';\nimport {get as getProjection, getTransformFromProjections, identityTransform} from './proj.js';\n\n\n/**\n * @typedef {Object} Options\n * @property {boolean} [tracking=false] Start Tracking right after\n * instantiation.\n * @property {GeolocationPositionOptions} [trackingOptions] Tracking options.\n * See {@link http://www.w3.org/TR/geolocation-API/#position_options_interface}.\n * @property {module:ol/proj~ProjectionLike} [projection] The projection the position\n * is reported in.\n */\n\n\n/**\n * @classdesc\n * Helper class for providing HTML5 Geolocation capabilities.\n * The [Geolocation API](http://www.w3.org/TR/geolocation-API/)\n * is used to locate a user's position.\n *\n * To get notified of position changes, register a listener for the generic\n * `change` event on your instance of {@link module:ol/Geolocation~Geolocation}.\n *\n * Example:\n *\n * var geolocation = new Geolocation({\n * // take the projection to use from the map's view\n * projection: view.getProjection()\n * });\n * // listen to changes in position\n * geolocation.on('change', function(evt) {\n * window.console.log(geolocation.getPosition());\n * });\n *\n * @fires error\n * @constructor\n * @extends {module:ol/Object}\n * @param {module:ol/Geolocation~Options=} opt_options Options.\n * @api\n */\nconst Geolocation = function(opt_options) {\n\n BaseObject.call(this);\n\n const options = opt_options || {};\n\n /**\n * The unprojected (EPSG:4326) device position.\n * @private\n * @type {module:ol/coordinate~Coordinate}\n */\n this.position_ = null;\n\n /**\n * @private\n * @type {module:ol/proj~TransformFunction}\n */\n this.transform_ = identityTransform;\n\n /**\n * @private\n * @type {number|undefined}\n */\n this.watchId_ = undefined;\n\n listen(\n this, getChangeEventType(GeolocationProperty.PROJECTION),\n this.handleProjectionChanged_, this);\n listen(\n this, getChangeEventType(GeolocationProperty.TRACKING),\n this.handleTrackingChanged_, this);\n\n if (options.projection !== undefined) {\n this.setProjection(options.projection);\n }\n if (options.trackingOptions !== undefined) {\n this.setTrackingOptions(options.trackingOptions);\n }\n\n this.setTracking(options.tracking !== undefined ? options.tracking : false);\n\n};\n\ninherits(Geolocation, BaseObject);\n\n\n/**\n * @inheritDoc\n */\nGeolocation.prototype.disposeInternal = function() {\n this.setTracking(false);\n BaseObject.prototype.disposeInternal.call(this);\n};\n\n\n/**\n * @private\n */\nGeolocation.prototype.handleProjectionChanged_ = function() {\n const projection = this.getProjection();\n if (projection) {\n this.transform_ = getTransformFromProjections(\n getProjection('EPSG:4326'), projection);\n if (this.position_) {\n this.set(GeolocationProperty.POSITION, this.transform_(this.position_));\n }\n }\n};\n\n\n/**\n * @private\n */\nGeolocation.prototype.handleTrackingChanged_ = function() {\n if (GEOLOCATION) {\n const tracking = this.getTracking();\n if (tracking && this.watchId_ === undefined) {\n this.watchId_ = navigator.geolocation.watchPosition(\n this.positionChange_.bind(this),\n this.positionError_.bind(this),\n this.getTrackingOptions());\n } else if (!tracking && this.watchId_ !== undefined) {\n navigator.geolocation.clearWatch(this.watchId_);\n this.watchId_ = undefined;\n }\n }\n};\n\n\n/**\n * @private\n * @param {GeolocationPosition} position position event.\n */\nGeolocation.prototype.positionChange_ = function(position) {\n const coords = position.coords;\n this.set(GeolocationProperty.ACCURACY, coords.accuracy);\n this.set(GeolocationProperty.ALTITUDE,\n coords.altitude === null ? undefined : coords.altitude);\n this.set(GeolocationProperty.ALTITUDE_ACCURACY,\n coords.altitudeAccuracy === null ?\n undefined : coords.altitudeAccuracy);\n this.set(GeolocationProperty.HEADING, coords.heading === null ?\n undefined : toRadians(coords.heading));\n if (!this.position_) {\n this.position_ = [coords.longitude, coords.latitude];\n } else {\n this.position_[0] = coords.longitude;\n this.position_[1] = coords.latitude;\n }\n const projectedPosition = this.transform_(this.position_);\n this.set(GeolocationProperty.POSITION, projectedPosition);\n this.set(GeolocationProperty.SPEED,\n coords.speed === null ? undefined : coords.speed);\n const geometry = circularPolygon(this.position_, coords.accuracy);\n geometry.applyTransform(this.transform_);\n this.set(GeolocationProperty.ACCURACY_GEOMETRY, geometry);\n this.changed();\n};\n\n/**\n * Triggered when the Geolocation returns an error.\n * @event error\n * @api\n */\n\n/**\n * @private\n * @param {GeolocationPositionError} error error object.\n */\nGeolocation.prototype.positionError_ = function(error) {\n error.type = EventType.ERROR;\n this.setTracking(false);\n this.dispatchEvent(/** @type {{type: string, target: undefined}} */ (error));\n};\n\n\n/**\n * Get the accuracy of the position in meters.\n * @return {number|undefined} The accuracy of the position measurement in\n * meters.\n * @observable\n * @api\n */\nGeolocation.prototype.getAccuracy = function() {\n return /** @type {number|undefined} */ (this.get(GeolocationProperty.ACCURACY));\n};\n\n\n/**\n * Get a geometry of the position accuracy.\n * @return {?module:ol/geom/Polygon} A geometry of the position accuracy.\n * @observable\n * @api\n */\nGeolocation.prototype.getAccuracyGeometry = function() {\n return (\n /** @type {?module:ol/geom/Polygon} */ (this.get(GeolocationProperty.ACCURACY_GEOMETRY) || null)\n );\n};\n\n\n/**\n * Get the altitude associated with the position.\n * @return {number|undefined} The altitude of the position in meters above mean\n * sea level.\n * @observable\n * @api\n */\nGeolocation.prototype.getAltitude = function() {\n return /** @type {number|undefined} */ (this.get(GeolocationProperty.ALTITUDE));\n};\n\n\n/**\n * Get the altitude accuracy of the position.\n * @return {number|undefined} The accuracy of the altitude measurement in\n * meters.\n * @observable\n * @api\n */\nGeolocation.prototype.getAltitudeAccuracy = function() {\n return /** @type {number|undefined} */ (this.get(GeolocationProperty.ALTITUDE_ACCURACY));\n};\n\n\n/**\n * Get the heading as radians clockwise from North.\n * Note: depending on the browser, the heading is only defined if the `enableHighAccuracy`\n * is set to `true` in the tracking options.\n * @return {number|undefined} The heading of the device in radians from north.\n * @observable\n * @api\n */\nGeolocation.prototype.getHeading = function() {\n return /** @type {number|undefined} */ (this.get(GeolocationProperty.HEADING));\n};\n\n\n/**\n * Get the position of the device.\n * @return {module:ol/coordinate~Coordinate|undefined} The current position of the device reported\n * in the current projection.\n * @observable\n * @api\n */\nGeolocation.prototype.getPosition = function() {\n return (\n /** @type {module:ol/coordinate~Coordinate|undefined} */ (this.get(GeolocationProperty.POSITION))\n );\n};\n\n\n/**\n * Get the projection associated with the position.\n * @return {module:ol/proj/Projection|undefined} The projection the position is\n * reported in.\n * @observable\n * @api\n */\nGeolocation.prototype.getProjection = function() {\n return (\n /** @type {module:ol/proj/Projection|undefined} */ (this.get(GeolocationProperty.PROJECTION))\n );\n};\n\n\n/**\n * Get the speed in meters per second.\n * @return {number|undefined} The instantaneous speed of the device in meters\n * per second.\n * @observable\n * @api\n */\nGeolocation.prototype.getSpeed = function() {\n return /** @type {number|undefined} */ (this.get(GeolocationProperty.SPEED));\n};\n\n\n/**\n * Determine if the device location is being tracked.\n * @return {boolean} The device location is being tracked.\n * @observable\n * @api\n */\nGeolocation.prototype.getTracking = function() {\n return /** @type {boolean} */ (this.get(GeolocationProperty.TRACKING));\n};\n\n\n/**\n * Get the tracking options.\n * @see http://www.w3.org/TR/geolocation-API/#position-options\n * @return {GeolocationPositionOptions|undefined} PositionOptions as defined by\n * the [HTML5 Geolocation spec\n * ](http://www.w3.org/TR/geolocation-API/#position_options_interface).\n * @observable\n * @api\n */\nGeolocation.prototype.getTrackingOptions = function() {\n return /** @type {GeolocationPositionOptions|undefined} */ (this.get(GeolocationProperty.TRACKING_OPTIONS));\n};\n\n\n/**\n * Set the projection to use for transforming the coordinates.\n * @param {module:ol/proj~ProjectionLike} projection The projection the position is\n * reported in.\n * @observable\n * @api\n */\nGeolocation.prototype.setProjection = function(projection) {\n this.set(GeolocationProperty.PROJECTION, getProjection(projection));\n};\n\n\n/**\n * Enable or disable tracking.\n * @param {boolean} tracking Enable tracking.\n * @observable\n * @api\n */\nGeolocation.prototype.setTracking = function(tracking) {\n this.set(GeolocationProperty.TRACKING, tracking);\n};\n\n\n/**\n * Set the tracking options.\n * @see http://www.w3.org/TR/geolocation-API/#position-options\n * @param {GeolocationPositionOptions} options PositionOptions as defined by the\n * [HTML5 Geolocation spec\n * ](http://www.w3.org/TR/geolocation-API/#position_options_interface).\n * @observable\n * @api\n */\nGeolocation.prototype.setTrackingOptions = function(options) {\n this.set(GeolocationProperty.TRACKING_OPTIONS, options);\n};\nexport default Geolocation;\n","/**\n * @module ol/string\n */\n\n/**\n * @param {number} number Number to be formatted\n * @param {number} width The desired width\n * @param {number=} opt_precision Precision of the output string (i.e. number of decimal places)\n * @returns {string} Formatted string\n */\nexport function padNumber(number, width, opt_precision) {\n const numberString = opt_precision !== undefined ? number.toFixed(opt_precision) : '' + number;\n let decimal = numberString.indexOf('.');\n decimal = decimal === -1 ? numberString.length : decimal;\n return decimal > width ? numberString : new Array(1 + width - decimal).join('0') + numberString;\n}\n\n\n/**\n * Adapted from https://github.com/omichelsen/compare-versions/blob/master/index.js\n * @param {string|number} v1 First version\n * @param {string|number} v2 Second version\n * @returns {number} Value\n */\nexport function compareVersions(v1, v2) {\n const s1 = ('' + v1).split('.');\n const s2 = ('' + v2).split('.');\n\n for (let i = 0; i < Math.max(s1.length, s2.length); i++) {\n const n1 = parseInt(s1[i] || '0', 10);\n const n2 = parseInt(s2[i] || '0', 10);\n\n if (n1 > n2) {\n return 1;\n }\n if (n2 > n1) {\n return -1;\n }\n }\n\n return 0;\n}\n","/**\n * @module ol/coordinate\n */\nimport {modulo} from './math.js';\nimport {padNumber} from './string.js';\n\n\n/**\n * An array of numbers representing an xy coordinate. Example: `[16, 48]`.\n * @typedef {Array.} Coordinate\n * @api\n */\n\n\n/**\n * A function that takes a {@link module:ol/coordinate~Coordinate} and\n * transforms it into a `{string}`.\n *\n * @typedef {function((module:ol/coordinate~Coordinate|undefined)): string} CoordinateFormat\n * @api\n */\n\n\n/**\n * Add `delta` to `coordinate`. `coordinate` is modified in place and returned\n * by the function.\n *\n * Example:\n *\n * import {add} from 'ol/coordinate';\n *\n * var coord = [7.85, 47.983333];\n * add(coord, [-2, 4]);\n * // coord is now [5.85, 51.983333]\n *\n * @param {module:ol/coordinate~Coordinate} coordinate Coordinate.\n * @param {module:ol/coordinate~Coordinate} delta Delta.\n * @return {module:ol/coordinate~Coordinate} The input coordinate adjusted by\n * the given delta.\n * @api\n */\nexport function add(coordinate, delta) {\n coordinate[0] += delta[0];\n coordinate[1] += delta[1];\n return coordinate;\n}\n\n\n/**\n * Calculates the point closest to the passed coordinate on the passed circle.\n *\n * @param {module:ol/coordinate~Coordinate} coordinate The coordinate.\n * @param {module:ol/geom/Circle} circle The circle.\n * @return {module:ol/coordinate~Coordinate} Closest point on the circumference.\n */\nexport function closestOnCircle(coordinate, circle) {\n const r = circle.getRadius();\n const center = circle.getCenter();\n const x0 = center[0];\n const y0 = center[1];\n const x1 = coordinate[0];\n const y1 = coordinate[1];\n\n let dx = x1 - x0;\n const dy = y1 - y0;\n if (dx === 0 && dy === 0) {\n dx = 1;\n }\n const d = Math.sqrt(dx * dx + dy * dy);\n\n const x = x0 + r * dx / d;\n const y = y0 + r * dy / d;\n\n return [x, y];\n}\n\n\n/**\n * Calculates the point closest to the passed coordinate on the passed segment.\n * This is the foot of the perpendicular of the coordinate to the segment when\n * the foot is on the segment, or the closest segment coordinate when the foot\n * is outside the segment.\n *\n * @param {module:ol/coordinate~Coordinate} coordinate The coordinate.\n * @param {Array.} segment The two coordinates\n * of the segment.\n * @return {module:ol/coordinate~Coordinate} The foot of the perpendicular of\n * the coordinate to the segment.\n */\nexport function closestOnSegment(coordinate, segment) {\n const x0 = coordinate[0];\n const y0 = coordinate[1];\n const start = segment[0];\n const end = segment[1];\n const x1 = start[0];\n const y1 = start[1];\n const x2 = end[0];\n const y2 = end[1];\n const dx = x2 - x1;\n const dy = y2 - y1;\n const along = (dx === 0 && dy === 0) ? 0 :\n ((dx * (x0 - x1)) + (dy * (y0 - y1))) / ((dx * dx + dy * dy) || 0);\n let x, y;\n if (along <= 0) {\n x = x1;\n y = y1;\n } else if (along >= 1) {\n x = x2;\n y = y2;\n } else {\n x = x1 + along * dx;\n y = y1 + along * dy;\n }\n return [x, y];\n}\n\n\n/**\n * Returns a {@link module:ol/coordinate~CoordinateFormat} function that can be\n * used to format\n * a {module:ol/coordinate~Coordinate} to a string.\n *\n * Example without specifying the fractional digits:\n *\n * import {createStringXY} from 'ol/coordinate';\n *\n * var coord = [7.85, 47.983333];\n * var stringifyFunc = createStringXY();\n * var out = stringifyFunc(coord);\n * // out is now '8, 48'\n *\n * Example with explicitly specifying 2 fractional digits:\n *\n * import {createStringXY} from 'ol/coordinate';\n *\n * var coord = [7.85, 47.983333];\n * var stringifyFunc = createStringXY(2);\n * var out = stringifyFunc(coord);\n * // out is now '7.85, 47.98'\n *\n * @param {number=} opt_fractionDigits The number of digits to include\n * after the decimal point. Default is `0`.\n * @return {module:ol/coordinate~CoordinateFormat} Coordinate format.\n * @api\n */\nexport function createStringXY(opt_fractionDigits) {\n return (\n /**\n * @param {module:ol/coordinate~Coordinate} coordinate Coordinate.\n * @return {string} String XY.\n */\n function(coordinate) {\n return toStringXY(coordinate, opt_fractionDigits);\n }\n );\n}\n\n\n/**\n * @param {string} hemispheres Hemispheres.\n * @param {number} degrees Degrees.\n * @param {number=} opt_fractionDigits The number of digits to include\n * after the decimal point. Default is `0`.\n * @return {string} String.\n */\nexport function degreesToStringHDMS(hemispheres, degrees, opt_fractionDigits) {\n const normalizedDegrees = modulo(degrees + 180, 360) - 180;\n const x = Math.abs(3600 * normalizedDegrees);\n const dflPrecision = opt_fractionDigits || 0;\n const precision = Math.pow(10, dflPrecision);\n\n let deg = Math.floor(x / 3600);\n let min = Math.floor((x - deg * 3600) / 60);\n let sec = x - (deg * 3600) - (min * 60);\n sec = Math.ceil(sec * precision) / precision;\n\n if (sec >= 60) {\n sec = 0;\n min += 1;\n }\n\n if (min >= 60) {\n min = 0;\n deg += 1;\n }\n\n return deg + '\\u00b0 ' + padNumber(min, 2) + '\\u2032 ' +\n padNumber(sec, 2, dflPrecision) + '\\u2033' +\n (normalizedDegrees == 0 ? '' : ' ' + hemispheres.charAt(normalizedDegrees < 0 ? 1 : 0));\n}\n\n\n/**\n * Transforms the given {@link module:ol/coordinate~Coordinate} to a string\n * using the given string template. The strings `{x}` and `{y}` in the template\n * will be replaced with the first and second coordinate values respectively.\n *\n * Example without specifying the fractional digits:\n *\n * import {format} from 'ol/coordinate';\n *\n * var coord = [7.85, 47.983333];\n * var template = 'Coordinate is ({x}|{y}).';\n * var out = format(coord, template);\n * // out is now 'Coordinate is (8|48).'\n *\n * Example explicitly specifying the fractional digits:\n *\n * import {format} from 'ol/coordinate';\n *\n * var coord = [7.85, 47.983333];\n * var template = 'Coordinate is ({x}|{y}).';\n * var out = format(coord, template, 2);\n * // out is now 'Coordinate is (7.85|47.98).'\n *\n * @param {module:ol/coordinate~Coordinate} coordinate Coordinate.\n * @param {string} template A template string with `{x}` and `{y}` placeholders\n * that will be replaced by first and second coordinate values.\n * @param {number=} opt_fractionDigits The number of digits to include\n * after the decimal point. Default is `0`.\n * @return {string} Formatted coordinate.\n * @api\n */\nexport function format(coordinate, template, opt_fractionDigits) {\n if (coordinate) {\n return template\n .replace('{x}', coordinate[0].toFixed(opt_fractionDigits))\n .replace('{y}', coordinate[1].toFixed(opt_fractionDigits));\n } else {\n return '';\n }\n}\n\n\n/**\n * @param {module:ol/coordinate~Coordinate} coordinate1 First coordinate.\n * @param {module:ol/coordinate~Coordinate} coordinate2 Second coordinate.\n * @return {boolean} The two coordinates are equal.\n */\nexport function equals(coordinate1, coordinate2) {\n let equals = true;\n for (let i = coordinate1.length - 1; i >= 0; --i) {\n if (coordinate1[i] != coordinate2[i]) {\n equals = false;\n break;\n }\n }\n return equals;\n}\n\n\n/**\n * Rotate `coordinate` by `angle`. `coordinate` is modified in place and\n * returned by the function.\n *\n * Example:\n *\n * import {rotate} from 'ol/coordinate';\n *\n * var coord = [7.85, 47.983333];\n * var rotateRadians = Math.PI / 2; // 90 degrees\n * rotate(coord, rotateRadians);\n * // coord is now [-47.983333, 7.85]\n *\n * @param {module:ol/coordinate~Coordinate} coordinate Coordinate.\n * @param {number} angle Angle in radian.\n * @return {module:ol/coordinate~Coordinate} Coordinate.\n * @api\n */\nexport function rotate(coordinate, angle) {\n const cosAngle = Math.cos(angle);\n const sinAngle = Math.sin(angle);\n const x = coordinate[0] * cosAngle - coordinate[1] * sinAngle;\n const y = coordinate[1] * cosAngle + coordinate[0] * sinAngle;\n coordinate[0] = x;\n coordinate[1] = y;\n return coordinate;\n}\n\n\n/**\n * Scale `coordinate` by `scale`. `coordinate` is modified in place and returned\n * by the function.\n *\n * Example:\n *\n * import {scale as scaleCoordinate} from 'ol/coordinate';\n *\n * var coord = [7.85, 47.983333];\n * var scale = 1.2;\n * scaleCoordinate(coord, scale);\n * // coord is now [9.42, 57.5799996]\n *\n * @param {module:ol/coordinate~Coordinate} coordinate Coordinate.\n * @param {number} scale Scale factor.\n * @return {module:ol/coordinate~Coordinate} Coordinate.\n */\nexport function scale(coordinate, scale) {\n coordinate[0] *= scale;\n coordinate[1] *= scale;\n return coordinate;\n}\n\n\n/**\n * @param {module:ol/coordinate~Coordinate} coord1 First coordinate.\n * @param {module:ol/coordinate~Coordinate} coord2 Second coordinate.\n * @return {number} Squared distance between coord1 and coord2.\n */\nexport function squaredDistance(coord1, coord2) {\n const dx = coord1[0] - coord2[0];\n const dy = coord1[1] - coord2[1];\n return dx * dx + dy * dy;\n}\n\n\n/**\n * @param {module:ol/coordinate~Coordinate} coord1 First coordinate.\n * @param {module:ol/coordinate~Coordinate} coord2 Second coordinate.\n * @return {number} Distance between coord1 and coord2.\n */\nexport function distance(coord1, coord2) {\n return Math.sqrt(squaredDistance(coord1, coord2));\n}\n\n\n/**\n * Calculate the squared distance from a coordinate to a line segment.\n *\n * @param {module:ol/coordinate~Coordinate} coordinate Coordinate of the point.\n * @param {Array.} segment Line segment (2\n * coordinates).\n * @return {number} Squared distance from the point to the line segment.\n */\nexport function squaredDistanceToSegment(coordinate, segment) {\n return squaredDistance(coordinate,\n closestOnSegment(coordinate, segment));\n}\n\n\n/**\n * Format a geographic coordinate with the hemisphere, degrees, minutes, and\n * seconds.\n *\n * Example without specifying fractional digits:\n *\n * import {toStringHDMS} from 'ol/coordinate';\n *\n * var coord = [7.85, 47.983333];\n * var out = toStringHDMS(coord);\n * // out is now '47° 58′ 60″ N 7° 50′ 60″ E'\n *\n * Example explicitly specifying 1 fractional digit:\n *\n * import {toStringHDMS} from 'ol/coordinate';\n *\n * var coord = [7.85, 47.983333];\n * var out = toStringHDMS(coord, 1);\n * // out is now '47° 58′ 60.0″ N 7° 50′ 60.0″ E'\n *\n * @param {module:ol/coordinate~Coordinate} coordinate Coordinate.\n * @param {number=} opt_fractionDigits The number of digits to include\n * after the decimal point. Default is `0`.\n * @return {string} Hemisphere, degrees, minutes and seconds.\n * @api\n */\nexport function toStringHDMS(coordinate, opt_fractionDigits) {\n if (coordinate) {\n return degreesToStringHDMS('NS', coordinate[1], opt_fractionDigits) + ' ' +\n degreesToStringHDMS('EW', coordinate[0], opt_fractionDigits);\n } else {\n return '';\n }\n}\n\n\n/**\n * Format a coordinate as a comma delimited string.\n *\n * Example without specifying fractional digits:\n *\n * import {toStringXY} from 'ol/coordinate';\n *\n * var coord = [7.85, 47.983333];\n * var out = toStringXY(coord);\n * // out is now '8, 48'\n *\n * Example explicitly specifying 1 fractional digit:\n *\n * import {toStringXY} from 'ol/coordinate';\n *\n * var coord = [7.85, 47.983333];\n * var out = toStringXY(coord, 1);\n * // out is now '7.8, 48.0'\n *\n * @param {module:ol/coordinate~Coordinate} coordinate Coordinate.\n * @param {number=} opt_fractionDigits The number of digits to include\n * after the decimal point. Default is `0`.\n * @return {string} XY.\n * @api\n */\nexport function toStringXY(coordinate, opt_fractionDigits) {\n return format(coordinate, '{x}, {y}', opt_fractionDigits);\n}\n","/**\n * @module ol/geom/flat/interpolate\n */\nimport {binarySearch} from '../../array.js';\nimport {lerp} from '../../math.js';\n\n\n/**\n * @param {Array.} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {number} end End.\n * @param {number} stride Stride.\n * @param {number} fraction Fraction.\n * @param {Array.=} opt_dest Destination.\n * @return {Array.} Destination.\n */\nexport function interpolatePoint(flatCoordinates, offset, end, stride, fraction, opt_dest) {\n let pointX = NaN;\n let pointY = NaN;\n const n = (end - offset) / stride;\n if (n === 1) {\n pointX = flatCoordinates[offset];\n pointY = flatCoordinates[offset + 1];\n } else if (n == 2) {\n pointX = (1 - fraction) * flatCoordinates[offset] +\n fraction * flatCoordinates[offset + stride];\n pointY = (1 - fraction) * flatCoordinates[offset + 1] +\n fraction * flatCoordinates[offset + stride + 1];\n } else if (n !== 0) {\n let x1 = flatCoordinates[offset];\n let y1 = flatCoordinates[offset + 1];\n let length = 0;\n const cumulativeLengths = [0];\n for (let i = offset + stride; i < end; i += stride) {\n const x2 = flatCoordinates[i];\n const y2 = flatCoordinates[i + 1];\n length += Math.sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1));\n cumulativeLengths.push(length);\n x1 = x2;\n y1 = y2;\n }\n const target = fraction * length;\n const index = binarySearch(cumulativeLengths, target);\n if (index < 0) {\n const t = (target - cumulativeLengths[-index - 2]) /\n (cumulativeLengths[-index - 1] - cumulativeLengths[-index - 2]);\n const o = offset + (-index - 2) * stride;\n pointX = lerp(\n flatCoordinates[o], flatCoordinates[o + stride], t);\n pointY = lerp(\n flatCoordinates[o + 1], flatCoordinates[o + stride + 1], t);\n } else {\n pointX = flatCoordinates[offset + index * stride];\n pointY = flatCoordinates[offset + index * stride + 1];\n }\n }\n if (opt_dest) {\n opt_dest[0] = pointX;\n opt_dest[1] = pointY;\n return opt_dest;\n } else {\n return [pointX, pointY];\n }\n}\n\n\n/**\n * @param {Array.} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {number} end End.\n * @param {number} stride Stride.\n * @param {number} m M.\n * @param {boolean} extrapolate Extrapolate.\n * @return {module:ol/coordinate~Coordinate} Coordinate.\n */\nexport function lineStringCoordinateAtM(flatCoordinates, offset, end, stride, m, extrapolate) {\n if (end == offset) {\n return null;\n }\n let coordinate;\n if (m < flatCoordinates[offset + stride - 1]) {\n if (extrapolate) {\n coordinate = flatCoordinates.slice(offset, offset + stride);\n coordinate[stride - 1] = m;\n return coordinate;\n } else {\n return null;\n }\n } else if (flatCoordinates[end - 1] < m) {\n if (extrapolate) {\n coordinate = flatCoordinates.slice(end - stride, end);\n coordinate[stride - 1] = m;\n return coordinate;\n } else {\n return null;\n }\n }\n // FIXME use O(1) search\n if (m == flatCoordinates[offset + stride - 1]) {\n return flatCoordinates.slice(offset, offset + stride);\n }\n let lo = offset / stride;\n let hi = end / stride;\n while (lo < hi) {\n const mid = (lo + hi) >> 1;\n if (m < flatCoordinates[(mid + 1) * stride - 1]) {\n hi = mid;\n } else {\n lo = mid + 1;\n }\n }\n const m0 = flatCoordinates[lo * stride - 1];\n if (m == m0) {\n return flatCoordinates.slice((lo - 1) * stride, (lo - 1) * stride + stride);\n }\n const m1 = flatCoordinates[(lo + 1) * stride - 1];\n const t = (m - m0) / (m1 - m0);\n coordinate = [];\n for (let i = 0; i < stride - 1; ++i) {\n coordinate.push(lerp(flatCoordinates[(lo - 1) * stride + i],\n flatCoordinates[lo * stride + i], t));\n }\n coordinate.push(m);\n return coordinate;\n}\n\n\n/**\n * @param {Array.} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {Array.} ends Ends.\n * @param {number} stride Stride.\n * @param {number} m M.\n * @param {boolean} extrapolate Extrapolate.\n * @param {boolean} interpolate Interpolate.\n * @return {module:ol/coordinate~Coordinate} Coordinate.\n */\nexport function lineStringsCoordinateAtM(\n flatCoordinates, offset, ends, stride, m, extrapolate, interpolate) {\n if (interpolate) {\n return lineStringCoordinateAtM(\n flatCoordinates, offset, ends[ends.length - 1], stride, m, extrapolate);\n }\n let coordinate;\n if (m < flatCoordinates[stride - 1]) {\n if (extrapolate) {\n coordinate = flatCoordinates.slice(0, stride);\n coordinate[stride - 1] = m;\n return coordinate;\n } else {\n return null;\n }\n }\n if (flatCoordinates[flatCoordinates.length - 1] < m) {\n if (extrapolate) {\n coordinate = flatCoordinates.slice(flatCoordinates.length - stride);\n coordinate[stride - 1] = m;\n return coordinate;\n } else {\n return null;\n }\n }\n for (let i = 0, ii = ends.length; i < ii; ++i) {\n const end = ends[i];\n if (offset == end) {\n continue;\n }\n if (m < flatCoordinates[offset + stride - 1]) {\n return null;\n } else if (m <= flatCoordinates[end - 1]) {\n return lineStringCoordinateAtM(\n flatCoordinates, offset, end, stride, m, false);\n }\n offset = end;\n }\n return null;\n}\n","/**\n * @module ol/geom/flat/length\n */\n\n\n/**\n * @param {Array.} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {number} end End.\n * @param {number} stride Stride.\n * @return {number} Length.\n */\nexport function lineStringLength(flatCoordinates, offset, end, stride) {\n let x1 = flatCoordinates[offset];\n let y1 = flatCoordinates[offset + 1];\n let length = 0;\n for (let i = offset + stride; i < end; i += stride) {\n const x2 = flatCoordinates[i];\n const y2 = flatCoordinates[i + 1];\n length += Math.sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1));\n x1 = x2;\n y1 = y2;\n }\n return length;\n}\n\n\n/**\n * @param {Array.} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {number} end End.\n * @param {number} stride Stride.\n * @return {number} Perimeter.\n */\nexport function linearRingLength(flatCoordinates, offset, end, stride) {\n let perimeter = lineStringLength(flatCoordinates, offset, end, stride);\n const dx = flatCoordinates[end - stride] - flatCoordinates[offset];\n const dy = flatCoordinates[end - stride + 1] - flatCoordinates[offset + 1];\n perimeter += Math.sqrt(dx * dx + dy * dy);\n return perimeter;\n}\n","/**\n * @module ol/geom/LineString\n */\nimport {inherits} from '../util.js';\nimport {extend} from '../array.js';\nimport {closestSquaredDistanceXY} from '../extent.js';\nimport GeometryLayout from '../geom/GeometryLayout.js';\nimport GeometryType from '../geom/GeometryType.js';\nimport SimpleGeometry from '../geom/SimpleGeometry.js';\nimport {assignClosestPoint, maxSquaredDelta} from '../geom/flat/closest.js';\nimport {deflateCoordinates} from '../geom/flat/deflate.js';\nimport {inflateCoordinates} from '../geom/flat/inflate.js';\nimport {interpolatePoint, lineStringCoordinateAtM} from '../geom/flat/interpolate.js';\nimport {intersectsLineString} from '../geom/flat/intersectsextent.js';\nimport {lineStringLength} from '../geom/flat/length.js';\nimport {forEach as forEachSegment} from '../geom/flat/segments.js';\nimport {douglasPeucker} from '../geom/flat/simplify.js';\n\n/**\n * @classdesc\n * Linestring geometry.\n *\n * @constructor\n * @extends {module:ol/geom/SimpleGeometry}\n * @param {Array.} coordinates Coordinates.\n * @param {module:ol/geom/GeometryLayout=} opt_layout Layout.\n * @api\n */\nconst LineString = function(coordinates, opt_layout) {\n\n SimpleGeometry.call(this);\n\n /**\n * @private\n * @type {module:ol/coordinate~Coordinate}\n */\n this.flatMidpoint_ = null;\n\n /**\n * @private\n * @type {number}\n */\n this.flatMidpointRevision_ = -1;\n\n /**\n * @private\n * @type {number}\n */\n this.maxDelta_ = -1;\n\n /**\n * @private\n * @type {number}\n */\n this.maxDeltaRevision_ = -1;\n\n this.setCoordinates(coordinates, opt_layout);\n\n};\n\ninherits(LineString, SimpleGeometry);\n\n\n/**\n * Append the passed coordinate to the coordinates of the linestring.\n * @param {module:ol/coordinate~Coordinate} coordinate Coordinate.\n * @api\n */\nLineString.prototype.appendCoordinate = function(coordinate) {\n if (!this.flatCoordinates) {\n this.flatCoordinates = coordinate.slice();\n } else {\n extend(this.flatCoordinates, coordinate);\n }\n this.changed();\n};\n\n\n/**\n * Make a complete copy of the geometry.\n * @return {!module:ol/geom/LineString} Clone.\n * @override\n * @api\n */\nLineString.prototype.clone = function() {\n const lineString = new LineString(null);\n lineString.setFlatCoordinates(this.layout, this.flatCoordinates.slice());\n return lineString;\n};\n\n\n/**\n * @inheritDoc\n */\nLineString.prototype.closestPointXY = function(x, y, closestPoint, minSquaredDistance) {\n if (minSquaredDistance < closestSquaredDistanceXY(this.getExtent(), x, y)) {\n return minSquaredDistance;\n }\n if (this.maxDeltaRevision_ != this.getRevision()) {\n this.maxDelta_ = Math.sqrt(maxSquaredDelta(\n this.flatCoordinates, 0, this.flatCoordinates.length, this.stride, 0));\n this.maxDeltaRevision_ = this.getRevision();\n }\n return assignClosestPoint(\n this.flatCoordinates, 0, this.flatCoordinates.length, this.stride,\n this.maxDelta_, false, x, y, closestPoint, minSquaredDistance);\n};\n\n\n/**\n * Iterate over each segment, calling the provided callback.\n * If the callback returns a truthy value the function returns that\n * value immediately. Otherwise the function returns `false`.\n *\n * @param {function(this: S, module:ol/coordinate~Coordinate, module:ol/coordinate~Coordinate): T} callback Function\n * called for each segment.\n * @return {T|boolean} Value.\n * @template T,S\n * @api\n */\nLineString.prototype.forEachSegment = function(callback) {\n return forEachSegment(this.flatCoordinates, 0, this.flatCoordinates.length, this.stride, callback);\n};\n\n\n/**\n * Returns the coordinate at `m` using linear interpolation, or `null` if no\n * such coordinate exists.\n *\n * `opt_extrapolate` controls extrapolation beyond the range of Ms in the\n * MultiLineString. If `opt_extrapolate` is `true` then Ms less than the first\n * M will return the first coordinate and Ms greater than the last M will\n * return the last coordinate.\n *\n * @param {number} m M.\n * @param {boolean=} opt_extrapolate Extrapolate. Default is `false`.\n * @return {module:ol/coordinate~Coordinate} Coordinate.\n * @api\n */\nLineString.prototype.getCoordinateAtM = function(m, opt_extrapolate) {\n if (this.layout != GeometryLayout.XYM &&\n this.layout != GeometryLayout.XYZM) {\n return null;\n }\n const extrapolate = opt_extrapolate !== undefined ? opt_extrapolate : false;\n return lineStringCoordinateAtM(this.flatCoordinates, 0,\n this.flatCoordinates.length, this.stride, m, extrapolate);\n};\n\n\n/**\n * Return the coordinates of the linestring.\n * @return {Array.} Coordinates.\n * @override\n * @api\n */\nLineString.prototype.getCoordinates = function() {\n return inflateCoordinates(\n this.flatCoordinates, 0, this.flatCoordinates.length, this.stride);\n};\n\n\n/**\n * Return the coordinate at the provided fraction along the linestring.\n * The `fraction` is a number between 0 and 1, where 0 is the start of the\n * linestring and 1 is the end.\n * @param {number} fraction Fraction.\n * @param {module:ol/coordinate~Coordinate=} opt_dest Optional coordinate whose values will\n * be modified. If not provided, a new coordinate will be returned.\n * @return {module:ol/coordinate~Coordinate} Coordinate of the interpolated point.\n * @api\n */\nLineString.prototype.getCoordinateAt = function(fraction, opt_dest) {\n return interpolatePoint(\n this.flatCoordinates, 0, this.flatCoordinates.length, this.stride,\n fraction, opt_dest);\n};\n\n\n/**\n * Return the length of the linestring on projected plane.\n * @return {number} Length (on projected plane).\n * @api\n */\nLineString.prototype.getLength = function() {\n return lineStringLength(\n this.flatCoordinates, 0, this.flatCoordinates.length, this.stride);\n};\n\n\n/**\n * @return {Array.} Flat midpoint.\n */\nLineString.prototype.getFlatMidpoint = function() {\n if (this.flatMidpointRevision_ != this.getRevision()) {\n this.flatMidpoint_ = this.getCoordinateAt(0.5, this.flatMidpoint_);\n this.flatMidpointRevision_ = this.getRevision();\n }\n return this.flatMidpoint_;\n};\n\n\n/**\n * @inheritDoc\n */\nLineString.prototype.getSimplifiedGeometryInternal = function(squaredTolerance) {\n const simplifiedFlatCoordinates = [];\n simplifiedFlatCoordinates.length = douglasPeucker(\n this.flatCoordinates, 0, this.flatCoordinates.length, this.stride,\n squaredTolerance, simplifiedFlatCoordinates, 0);\n const simplifiedLineString = new LineString(null);\n simplifiedLineString.setFlatCoordinates(\n GeometryLayout.XY, simplifiedFlatCoordinates);\n return simplifiedLineString;\n};\n\n\n/**\n * @inheritDoc\n * @api\n */\nLineString.prototype.getType = function() {\n return GeometryType.LINE_STRING;\n};\n\n\n/**\n * @inheritDoc\n * @api\n */\nLineString.prototype.intersectsExtent = function(extent) {\n return intersectsLineString(\n this.flatCoordinates, 0, this.flatCoordinates.length, this.stride,\n extent);\n};\n\n\n/**\n * Set the coordinates of the linestring.\n * @param {Array.} coordinates Coordinates.\n * @param {module:ol/geom/GeometryLayout=} opt_layout Layout.\n * @override\n * @api\n */\nLineString.prototype.setCoordinates = function(coordinates, opt_layout) {\n if (!coordinates) {\n this.setFlatCoordinates(GeometryLayout.XY, null);\n } else {\n this.setLayout(opt_layout, coordinates, 1);\n if (!this.flatCoordinates) {\n this.flatCoordinates = [];\n }\n this.flatCoordinates.length = deflateCoordinates(\n this.flatCoordinates, 0, coordinates, this.stride);\n this.changed();\n }\n};\n\n\n/**\n * @param {module:ol/geom/GeometryLayout} layout Layout.\n * @param {Array.} flatCoordinates Flat coordinates.\n */\nLineString.prototype.setFlatCoordinates = function(layout, flatCoordinates) {\n this.setFlatCoordinatesInternal(layout, flatCoordinates);\n this.changed();\n};\nexport default LineString;\n","/**\n * @module ol/geom/flat/geodesic\n */\nimport {squaredSegmentDistance, toRadians, toDegrees} from '../../math.js';\nimport {get as getProjection, getTransform} from '../../proj.js';\n\n\n/**\n * @param {function(number): module:ol/coordinate~Coordinate} interpolate Interpolate function.\n * @param {module:ol/proj~TransformFunction} transform Transform from longitude/latitude to\n * projected coordinates.\n * @param {number} squaredTolerance Squared tolerance.\n * @return {Array.} Flat coordinates.\n */\nfunction line(interpolate, transform, squaredTolerance) {\n // FIXME reduce garbage generation\n // FIXME optimize stack operations\n\n /** @type {Array.} */\n const flatCoordinates = [];\n\n let geoA = interpolate(0);\n let geoB = interpolate(1);\n\n let a = transform(geoA);\n let b = transform(geoB);\n\n /** @type {Array.} */\n const geoStack = [geoB, geoA];\n /** @type {Array.} */\n const stack = [b, a];\n /** @type {Array.} */\n const fractionStack = [1, 0];\n\n /** @type {!Object.} */\n const fractions = {};\n\n let maxIterations = 1e5;\n let geoM, m, fracA, fracB, fracM, key;\n\n while (--maxIterations > 0 && fractionStack.length > 0) {\n // Pop the a coordinate off the stack\n fracA = fractionStack.pop();\n geoA = geoStack.pop();\n a = stack.pop();\n // Add the a coordinate if it has not been added yet\n key = fracA.toString();\n if (!(key in fractions)) {\n flatCoordinates.push(a[0], a[1]);\n fractions[key] = true;\n }\n // Pop the b coordinate off the stack\n fracB = fractionStack.pop();\n geoB = geoStack.pop();\n b = stack.pop();\n // Find the m point between the a and b coordinates\n fracM = (fracA + fracB) / 2;\n geoM = interpolate(fracM);\n m = transform(geoM);\n if (squaredSegmentDistance(m[0], m[1], a[0], a[1],\n b[0], b[1]) < squaredTolerance) {\n // If the m point is sufficiently close to the straight line, then we\n // discard it. Just use the b coordinate and move on to the next line\n // segment.\n flatCoordinates.push(b[0], b[1]);\n key = fracB.toString();\n fractions[key] = true;\n } else {\n // Otherwise, we need to subdivide the current line segment. Split it\n // into two and push the two line segments onto the stack.\n fractionStack.push(fracB, fracM, fracM, fracA);\n stack.push(b, m, m, a);\n geoStack.push(geoB, geoM, geoM, geoA);\n }\n }\n\n return flatCoordinates;\n}\n\n\n/**\n * Generate a great-circle arcs between two lat/lon points.\n * @param {number} lon1 Longitude 1 in degrees.\n * @param {number} lat1 Latitude 1 in degrees.\n * @param {number} lon2 Longitude 2 in degrees.\n * @param {number} lat2 Latitude 2 in degrees.\n * @param {module:ol/proj/Projection} projection Projection.\n * @param {number} squaredTolerance Squared tolerance.\n * @return {Array.} Flat coordinates.\n */\nexport function greatCircleArc(lon1, lat1, lon2, lat2, projection, squaredTolerance) {\n const geoProjection = getProjection('EPSG:4326');\n\n const cosLat1 = Math.cos(toRadians(lat1));\n const sinLat1 = Math.sin(toRadians(lat1));\n const cosLat2 = Math.cos(toRadians(lat2));\n const sinLat2 = Math.sin(toRadians(lat2));\n const cosDeltaLon = Math.cos(toRadians(lon2 - lon1));\n const sinDeltaLon = Math.sin(toRadians(lon2 - lon1));\n const d = sinLat1 * sinLat2 + cosLat1 * cosLat2 * cosDeltaLon;\n\n return line(\n /**\n * @param {number} frac Fraction.\n * @return {module:ol/coordinate~Coordinate} Coordinate.\n */\n function(frac) {\n if (1 <= d) {\n return [lon2, lat2];\n }\n const D = frac * Math.acos(d);\n const cosD = Math.cos(D);\n const sinD = Math.sin(D);\n const y = sinDeltaLon * cosLat2;\n const x = cosLat1 * sinLat2 - sinLat1 * cosLat2 * cosDeltaLon;\n const theta = Math.atan2(y, x);\n const lat = Math.asin(sinLat1 * cosD + cosLat1 * sinD * Math.cos(theta));\n const lon = toRadians(lon1) +\n Math.atan2(Math.sin(theta) * sinD * cosLat1,\n cosD - sinLat1 * Math.sin(lat));\n return [toDegrees(lon), toDegrees(lat)];\n }, getTransform(geoProjection, projection), squaredTolerance);\n}\n\n\n/**\n * Generate a meridian (line at constant longitude).\n * @param {number} lon Longitude.\n * @param {number} lat1 Latitude 1.\n * @param {number} lat2 Latitude 2.\n * @param {module:ol/proj/Projection} projection Projection.\n * @param {number} squaredTolerance Squared tolerance.\n * @return {Array.} Flat coordinates.\n */\nexport function meridian(lon, lat1, lat2, projection, squaredTolerance) {\n const epsg4326Projection = getProjection('EPSG:4326');\n return line(\n /**\n * @param {number} frac Fraction.\n * @return {module:ol/coordinate~Coordinate} Coordinate.\n */\n function(frac) {\n return [lon, lat1 + ((lat2 - lat1) * frac)];\n },\n getTransform(epsg4326Projection, projection), squaredTolerance);\n}\n\n\n/**\n * Generate a parallel (line at constant latitude).\n * @param {number} lat Latitude.\n * @param {number} lon1 Longitude 1.\n * @param {number} lon2 Longitude 2.\n * @param {module:ol/proj/Projection} projection Projection.\n * @param {number} squaredTolerance Squared tolerance.\n * @return {Array.} Flat coordinates.\n */\nexport function parallel(lat, lon1, lon2, projection, squaredTolerance) {\n const epsg4326Projection = getProjection('EPSG:4326');\n return line(\n /**\n * @param {number} frac Fraction.\n * @return {module:ol/coordinate~Coordinate} Coordinate.\n */\n function(frac) {\n return [lon1 + ((lon2 - lon1) * frac), lat];\n },\n getTransform(epsg4326Projection, projection), squaredTolerance);\n}\n","/**\n * @module ol/render/EventType\n */\n\n/**\n * @enum {string}\n */\nexport default {\n /**\n * @event module:ol/render/Event~RenderEvent#postcompose\n * @api\n */\n POSTCOMPOSE: 'postcompose',\n /**\n * @event module:ol/render/Event~RenderEvent#precompose\n * @api\n */\n PRECOMPOSE: 'precompose',\n /**\n * @event module:ol/render/Event~RenderEvent#render\n * @api\n */\n RENDER: 'render'\n};\n","/**\n * @module ol/style/TextPlacement\n */\n\n/**\n * Text placement. One of `'point'`, `'line'`. Default is `'point'`. Note that\n * `'line'` requires the underlying geometry to be a {@link module:ol/geom/LineString~LineString},\n * {@link module:ol/geom/Polygon~Polygon}, {@link module:ol/geom/MultiLineString~MultiLineString} or\n * {@link module:ol/geom/MultiPolygon~MultiPolygon}.\n * @enum {string}\n */\nexport default {\n POINT: 'point',\n LINE: 'line'\n};\n","/**\n * @module ol/style/Text\n */\nimport Fill from '../style/Fill.js';\nimport TextPlacement from '../style/TextPlacement.js';\n\n\n/**\n * The default fill color to use if no fill was set at construction time; a\n * blackish `#333`.\n *\n * @const {string}\n */\nconst DEFAULT_FILL_COLOR = '#333';\n\n\n/**\n * @typedef {Object} Options\n * @property {string} [font] Font style as CSS 'font' value, see:\n * {@link https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/font}. Default is '10px sans-serif'\n * @property {number} [maxAngle] When `placement` is set to `'line'`, allow a maximum angle between adjacent characters.\n * The expected value is in radians, and the default is 45° (`Math.PI / 4`).\n * @property {number} [offsetX=0] Horizontal text offset in pixels. A positive will shift the text right.\n * @property {number} [offsetY=0] Vertical text offset in pixels. A positive will shift the text down.\n * @property {boolean} [overflow=false] For polygon labels or when `placement` is set to `'line'`, allow text to exceed\n * the width of the polygon at the label position or the length of the path that it follows.\n * @property {module:ol/style/TextPlacement|string} [placement] Text placement.\n * @property {number} [scale] Scale.\n * @property {boolean} [rotateWithView=false] Whether to rotate the text with the view.\n * @property {number} [rotation=0] Rotation in radians (positive rotation clockwise).\n * @property {string} [text] Text content.\n * @property {string} [textAlign] Text alignment. Possible values: 'left', 'right', 'center', 'end' or 'start'.\n * Default is 'center' for `placement: 'point'`. For `placement: 'line'`, the default is to let the renderer choose a\n * placement where `maxAngle` is not exceeded.\n * @property {string} [textBaseline='middle'] Text base line. Possible values: 'bottom', 'top', 'middle', 'alphabetic',\n * 'hanging', 'ideographic'.\n * @property {module:ol/style/Fill} [fill] Fill style. If none is provided, we'll use a dark fill-style (#333).\n * @property {module:ol/style/Stroke} [stroke] Stroke style.\n * @property {module:ol/style/Fill} [backgroundFill] Fill style for the text background when `placement` is\n * `'point'`. Default is no fill.\n * @property {module:ol/style/Stroke} [backgroundStroke] Stroke style for the text background when `placement`\n * is `'point'`. Default is no stroke.\n * @property {Array.} [padding=[0, 0, 0, 0]] Padding in pixels around the text for decluttering and background. The order of\n * values in the array is `[top, right, bottom, left]`.\n */\n\n\n/**\n * @classdesc\n * Set text style for vector features.\n *\n * @constructor\n * @param {module:ol/style/Text~Options=} opt_options Options.\n * @api\n */\nconst Text = function(opt_options) {\n\n const options = opt_options || {};\n\n /**\n * @private\n * @type {string|undefined}\n */\n this.font_ = options.font;\n\n /**\n * @private\n * @type {number|undefined}\n */\n this.rotation_ = options.rotation;\n\n /**\n * @private\n * @type {boolean|undefined}\n */\n this.rotateWithView_ = options.rotateWithView;\n\n /**\n * @private\n * @type {number|undefined}\n */\n this.scale_ = options.scale;\n\n /**\n * @private\n * @type {string|undefined}\n */\n this.text_ = options.text;\n\n /**\n * @private\n * @type {string|undefined}\n */\n this.textAlign_ = options.textAlign;\n\n /**\n * @private\n * @type {string|undefined}\n */\n this.textBaseline_ = options.textBaseline;\n\n /**\n * @private\n * @type {module:ol/style/Fill}\n */\n this.fill_ = options.fill !== undefined ? options.fill :\n new Fill({color: DEFAULT_FILL_COLOR});\n\n /**\n * @private\n * @type {number}\n */\n this.maxAngle_ = options.maxAngle !== undefined ? options.maxAngle : Math.PI / 4;\n\n /**\n * @private\n * @type {module:ol/style/TextPlacement|string}\n */\n this.placement_ = options.placement !== undefined ? options.placement : TextPlacement.POINT;\n\n /**\n * @private\n * @type {boolean}\n */\n this.overflow_ = !!options.overflow;\n\n /**\n * @private\n * @type {module:ol/style/Stroke}\n */\n this.stroke_ = options.stroke !== undefined ? options.stroke : null;\n\n /**\n * @private\n * @type {number}\n */\n this.offsetX_ = options.offsetX !== undefined ? options.offsetX : 0;\n\n /**\n * @private\n * @type {number}\n */\n this.offsetY_ = options.offsetY !== undefined ? options.offsetY : 0;\n\n /**\n * @private\n * @type {module:ol/style/Fill}\n */\n this.backgroundFill_ = options.backgroundFill ? options.backgroundFill : null;\n\n /**\n * @private\n * @type {module:ol/style/Stroke}\n */\n this.backgroundStroke_ = options.backgroundStroke ? options.backgroundStroke : null;\n\n /**\n * @private\n * @type {Array.}\n */\n this.padding_ = options.padding === undefined ? null : options.padding;\n};\n\n\n/**\n * Clones the style.\n * @return {module:ol/style/Text} The cloned style.\n * @api\n */\nText.prototype.clone = function() {\n return new Text({\n font: this.getFont(),\n placement: this.getPlacement(),\n maxAngle: this.getMaxAngle(),\n overflow: this.getOverflow(),\n rotation: this.getRotation(),\n rotateWithView: this.getRotateWithView(),\n scale: this.getScale(),\n text: this.getText(),\n textAlign: this.getTextAlign(),\n textBaseline: this.getTextBaseline(),\n fill: this.getFill() ? this.getFill().clone() : undefined,\n stroke: this.getStroke() ? this.getStroke().clone() : undefined,\n offsetX: this.getOffsetX(),\n offsetY: this.getOffsetY(),\n backgroundFill: this.getBackgroundFill() ? this.getBackgroundFill().clone() : undefined,\n backgroundStroke: this.getBackgroundStroke() ? this.getBackgroundStroke().clone() : undefined\n });\n};\n\n\n/**\n * Get the `overflow` configuration.\n * @return {boolean} Let text overflow the length of the path they follow.\n * @api\n */\nText.prototype.getOverflow = function() {\n return this.overflow_;\n};\n\n\n/**\n * Get the font name.\n * @return {string|undefined} Font.\n * @api\n */\nText.prototype.getFont = function() {\n return this.font_;\n};\n\n\n/**\n * Get the maximum angle between adjacent characters.\n * @return {number} Angle in radians.\n * @api\n */\nText.prototype.getMaxAngle = function() {\n return this.maxAngle_;\n};\n\n\n/**\n * Get the label placement.\n * @return {module:ol/style/TextPlacement|string} Text placement.\n * @api\n */\nText.prototype.getPlacement = function() {\n return this.placement_;\n};\n\n\n/**\n * Get the x-offset for the text.\n * @return {number} Horizontal text offset.\n * @api\n */\nText.prototype.getOffsetX = function() {\n return this.offsetX_;\n};\n\n\n/**\n * Get the y-offset for the text.\n * @return {number} Vertical text offset.\n * @api\n */\nText.prototype.getOffsetY = function() {\n return this.offsetY_;\n};\n\n\n/**\n * Get the fill style for the text.\n * @return {module:ol/style/Fill} Fill style.\n * @api\n */\nText.prototype.getFill = function() {\n return this.fill_;\n};\n\n\n/**\n * Determine whether the text rotates with the map.\n * @return {boolean|undefined} Rotate with map.\n * @api\n */\nText.prototype.getRotateWithView = function() {\n return this.rotateWithView_;\n};\n\n\n/**\n * Get the text rotation.\n * @return {number|undefined} Rotation.\n * @api\n */\nText.prototype.getRotation = function() {\n return this.rotation_;\n};\n\n\n/**\n * Get the text scale.\n * @return {number|undefined} Scale.\n * @api\n */\nText.prototype.getScale = function() {\n return this.scale_;\n};\n\n\n/**\n * Get the stroke style for the text.\n * @return {module:ol/style/Stroke} Stroke style.\n * @api\n */\nText.prototype.getStroke = function() {\n return this.stroke_;\n};\n\n\n/**\n * Get the text to be rendered.\n * @return {string|undefined} Text.\n * @api\n */\nText.prototype.getText = function() {\n return this.text_;\n};\n\n\n/**\n * Get the text alignment.\n * @return {string|undefined} Text align.\n * @api\n */\nText.prototype.getTextAlign = function() {\n return this.textAlign_;\n};\n\n\n/**\n * Get the text baseline.\n * @return {string|undefined} Text baseline.\n * @api\n */\nText.prototype.getTextBaseline = function() {\n return this.textBaseline_;\n};\n\n\n/**\n * Get the background fill style for the text.\n * @return {module:ol/style/Fill} Fill style.\n * @api\n */\nText.prototype.getBackgroundFill = function() {\n return this.backgroundFill_;\n};\n\n\n/**\n * Get the background stroke style for the text.\n * @return {module:ol/style/Stroke} Stroke style.\n * @api\n */\nText.prototype.getBackgroundStroke = function() {\n return this.backgroundStroke_;\n};\n\n\n/**\n * Get the padding for the text.\n * @return {Array.} Padding.\n * @api\n */\nText.prototype.getPadding = function() {\n return this.padding_;\n};\n\n\n/**\n * Set the `overflow` property.\n *\n * @param {boolean} overflow Let text overflow the path that it follows.\n * @api\n */\nText.prototype.setOverflow = function(overflow) {\n this.overflow_ = overflow;\n};\n\n\n/**\n * Set the font.\n *\n * @param {string|undefined} font Font.\n * @api\n */\nText.prototype.setFont = function(font) {\n this.font_ = font;\n};\n\n\n/**\n * Set the maximum angle between adjacent characters.\n *\n * @param {number} maxAngle Angle in radians.\n * @api\n */\nText.prototype.setMaxAngle = function(maxAngle) {\n this.maxAngle_ = maxAngle;\n};\n\n\n/**\n * Set the x offset.\n *\n * @param {number} offsetX Horizontal text offset.\n * @api\n */\nText.prototype.setOffsetX = function(offsetX) {\n this.offsetX_ = offsetX;\n};\n\n\n/**\n * Set the y offset.\n *\n * @param {number} offsetY Vertical text offset.\n * @api\n */\nText.prototype.setOffsetY = function(offsetY) {\n this.offsetY_ = offsetY;\n};\n\n\n/**\n * Set the text placement.\n *\n * @param {module:ol/style/TextPlacement|string} placement Placement.\n * @api\n */\nText.prototype.setPlacement = function(placement) {\n this.placement_ = placement;\n};\n\n\n/**\n * Set the fill.\n *\n * @param {module:ol/style/Fill} fill Fill style.\n * @api\n */\nText.prototype.setFill = function(fill) {\n this.fill_ = fill;\n};\n\n\n/**\n * Set the rotation.\n *\n * @param {number|undefined} rotation Rotation.\n * @api\n */\nText.prototype.setRotation = function(rotation) {\n this.rotation_ = rotation;\n};\n\n\n/**\n * Set the scale.\n *\n * @param {number|undefined} scale Scale.\n * @api\n */\nText.prototype.setScale = function(scale) {\n this.scale_ = scale;\n};\n\n\n/**\n * Set the stroke.\n *\n * @param {module:ol/style/Stroke} stroke Stroke style.\n * @api\n */\nText.prototype.setStroke = function(stroke) {\n this.stroke_ = stroke;\n};\n\n\n/**\n * Set the text.\n *\n * @param {string|undefined} text Text.\n * @api\n */\nText.prototype.setText = function(text) {\n this.text_ = text;\n};\n\n\n/**\n * Set the text alignment.\n *\n * @param {string|undefined} textAlign Text align.\n * @api\n */\nText.prototype.setTextAlign = function(textAlign) {\n this.textAlign_ = textAlign;\n};\n\n\n/**\n * Set the text baseline.\n *\n * @param {string|undefined} textBaseline Text baseline.\n * @api\n */\nText.prototype.setTextBaseline = function(textBaseline) {\n this.textBaseline_ = textBaseline;\n};\n\n\n/**\n * Set the background fill.\n *\n * @param {module:ol/style/Fill} fill Fill style.\n * @api\n */\nText.prototype.setBackgroundFill = function(fill) {\n this.backgroundFill_ = fill;\n};\n\n\n/**\n * Set the background stroke.\n *\n * @param {module:ol/style/Stroke} stroke Stroke style.\n * @api\n */\nText.prototype.setBackgroundStroke = function(stroke) {\n this.backgroundStroke_ = stroke;\n};\n\n\n/**\n * Set the padding (`[top, right, bottom, left]`).\n *\n * @param {!Array.} padding Padding.\n * @api\n */\nText.prototype.setPadding = function(padding) {\n this.padding_ = padding;\n};\nexport default Text;\n","/**\n * @module ol/Graticule\n */\nimport {degreesToStringHDMS} from './coordinate.js';\nimport {listen, unlistenByKey} from './events.js';\nimport {intersects, getCenter} from './extent.js';\nimport GeometryLayout from './geom/GeometryLayout.js';\nimport LineString from './geom/LineString.js';\nimport Point from './geom/Point.js';\nimport {meridian, parallel} from './geom/flat/geodesic.js';\nimport {clamp} from './math.js';\nimport {get as getProjection, equivalent as equivalentProjection, getTransform, transformExtent} from './proj.js';\nimport RenderEventType from './render/EventType.js';\nimport Fill from './style/Fill.js';\nimport Stroke from './style/Stroke.js';\nimport Text from './style/Text.js';\n\n\n/**\n * @type {module:ol/style/Stroke}\n * @private\n * @const\n */\nconst DEFAULT_STROKE_STYLE = new Stroke({\n color: 'rgba(0,0,0,0.2)'\n});\n\n/**\n * TODO can be configurable\n * @type {Array.}\n * @private\n */\nconst INTERVALS = [\n 90, 45, 30, 20, 10, 5, 2, 1, 0.5, 0.2, 0.1, 0.05, 0.01, 0.005, 0.002, 0.001\n];\n\n/**\n * @typedef {Object} GraticuleLabelDataType\n * @property {module:ol/geom/Point} geom\n * @property {string} text\n */\n\n/**\n * @typedef {Object} Options\n * @property {module:ol/PluggableMap} [map] Reference to an\n * {@link module:ol/Map~Map} object.\n * @property {number} [maxLines=100] The maximum number of meridians and\n * parallels from the center of the map. The default value of 100 means that at\n * most 200 meridians and 200 parallels will be displayed. The default value is\n * appropriate for conformal projections like Spherical Mercator. If you\n * increase the value, more lines will be drawn and the drawing performance will\n * decrease.\n * @property {module:ol/style/Stroke} [strokeStyle='rgba(0,0,0,0.2)'] The\n * stroke style to use for drawing the graticule. If not provided, a not fully\n * opaque black will be used.\n * @property {number} [targetSize=100] The target size of the graticule cells,\n * in pixels.\n * @property {boolean} [showLabels=false] Render a label with the respective\n * latitude/longitude for each graticule line.\n * @property {function(number):string} [lonLabelFormatter] Label formatter for\n * longitudes. This function is called with the longitude as argument, and\n * should return a formatted string representing the longitude. By default,\n * labels are formatted as degrees, minutes, seconds and hemisphere.\n * @property {function(number):string} [latLabelFormatter] Label formatter for\n * latitudes. This function is called with the latitude as argument, and\n * should return a formatted string representing the latitude. By default,\n * labels are formatted as degrees, minutes, seconds and hemisphere.\n * @property {number} [lonLabelPosition=0] Longitude label position in fractions\n * (0..1) of view extent. 0 means at the bottom of the viewport, 1 means at the\n * top.\n * @property {number} [latLabelPosition=1] Latitude label position in fractions\n * (0..1) of view extent. 0 means at the left of the viewport, 1 means at the\n * right.\n * @property {module:ol/style/Text} [lonLabelStyle] Longitude label text\n * style. If not provided, the following style will be used:\n * ```js\n * new Text({\n * font: '12px Calibri,sans-serif',\n * textBaseline: 'bottom',\n * fill: new Fill({\n * color: 'rgba(0,0,0,1)'\n * }),\n * stroke: new Stroke({\n * color: 'rgba(255,255,255,1)',\n * width: 3\n * })\n * });\n * ```\n * Note that the default's `textBaseline` configuration will not work well for\n * `lonLabelPosition` configurations that position labels close to the top of\n * the viewport.\n * @property {module:ol/style/Text} [latLabelStyle] Latitude label text style.\n * If not provided, the following style will be used:\n * ```js\n * new Text({\n * font: '12px Calibri,sans-serif',\n * textAlign: 'end',\n * fill: new Fill({\n * color: 'rgba(0,0,0,1)'\n * }),\n * stroke: Stroke({\n * color: 'rgba(255,255,255,1)',\n * width: 3\n * })\n * });\n * ```\n * Note that the default's `textAlign` configuration will not work well for\n * `latLabelPosition` configurations that position labels close to the left of\n * the viewport.\n */\n\n\n/**\n * Render a grid for a coordinate system on a map.\n * @constructor\n * @param {module:ol/Graticule~Options=} opt_options Options.\n * @api\n */\nconst Graticule = function(opt_options) {\n const options = opt_options || {};\n\n /**\n * @type {module:ol/PluggableMap}\n * @private\n */\n this.map_ = null;\n\n /**\n * @type {?module:ol/events~EventsKey}\n * @private\n */\n this.postcomposeListenerKey_ = null;\n\n /**\n * @type {module:ol/proj/Projection}\n */\n this.projection_ = null;\n\n /**\n * @type {number}\n * @private\n */\n this.maxLat_ = Infinity;\n\n /**\n * @type {number}\n * @private\n */\n this.maxLon_ = Infinity;\n\n /**\n * @type {number}\n * @private\n */\n this.minLat_ = -Infinity;\n\n /**\n * @type {number}\n * @private\n */\n this.minLon_ = -Infinity;\n\n /**\n * @type {number}\n * @private\n */\n this.maxLatP_ = Infinity;\n\n /**\n * @type {number}\n * @private\n */\n this.maxLonP_ = Infinity;\n\n /**\n * @type {number}\n * @private\n */\n this.minLatP_ = -Infinity;\n\n /**\n * @type {number}\n * @private\n */\n this.minLonP_ = -Infinity;\n\n /**\n * @type {number}\n * @private\n */\n this.targetSize_ = options.targetSize !== undefined ? options.targetSize : 100;\n\n /**\n * @type {number}\n * @private\n */\n this.maxLines_ = options.maxLines !== undefined ? options.maxLines : 100;\n\n /**\n * @type {Array.}\n * @private\n */\n this.meridians_ = [];\n\n /**\n * @type {Array.}\n * @private\n */\n this.parallels_ = [];\n\n /**\n * @type {module:ol/style/Stroke}\n * @private\n */\n this.strokeStyle_ = options.strokeStyle !== undefined ? options.strokeStyle : DEFAULT_STROKE_STYLE;\n\n /**\n * @type {module:ol/proj~TransformFunction|undefined}\n * @private\n */\n this.fromLonLatTransform_ = undefined;\n\n /**\n * @type {module:ol/proj~TransformFunction|undefined}\n * @private\n */\n this.toLonLatTransform_ = undefined;\n\n /**\n * @type {module:ol/coordinate~Coordinate}\n * @private\n */\n this.projectionCenterLonLat_ = null;\n\n /**\n * @type {Array.}\n * @private\n */\n this.meridiansLabels_ = null;\n\n /**\n * @type {Array.}\n * @private\n */\n this.parallelsLabels_ = null;\n\n if (options.showLabels == true) {\n\n /**\n * @type {null|function(number):string}\n * @private\n */\n this.lonLabelFormatter_ = options.lonLabelFormatter == undefined ?\n degreesToStringHDMS.bind(this, 'EW') : options.lonLabelFormatter;\n\n /**\n * @type {function(number):string}\n * @private\n */\n this.latLabelFormatter_ = options.latLabelFormatter == undefined ?\n degreesToStringHDMS.bind(this, 'NS') : options.latLabelFormatter;\n\n /**\n * Longitude label position in fractions (0..1) of view extent. 0 means\n * bottom, 1 means top.\n * @type {number}\n * @private\n */\n this.lonLabelPosition_ = options.lonLabelPosition == undefined ? 0 :\n options.lonLabelPosition;\n\n /**\n * Latitude Label position in fractions (0..1) of view extent. 0 means left, 1\n * means right.\n * @type {number}\n * @private\n */\n this.latLabelPosition_ = options.latLabelPosition == undefined ? 1 :\n options.latLabelPosition;\n\n /**\n * @type {module:ol/style/Text}\n * @private\n */\n this.lonLabelStyle_ = options.lonLabelStyle !== undefined ? options.lonLabelStyle :\n new Text({\n font: '12px Calibri,sans-serif',\n textBaseline: 'bottom',\n fill: new Fill({\n color: 'rgba(0,0,0,1)'\n }),\n stroke: new Stroke({\n color: 'rgba(255,255,255,1)',\n width: 3\n })\n });\n\n /**\n * @type {module:ol/style/Text}\n * @private\n */\n this.latLabelStyle_ = options.latLabelStyle !== undefined ? options.latLabelStyle :\n new Text({\n font: '12px Calibri,sans-serif',\n textAlign: 'end',\n fill: new Fill({\n color: 'rgba(0,0,0,1)'\n }),\n stroke: new Stroke({\n color: 'rgba(255,255,255,1)',\n width: 3\n })\n });\n\n this.meridiansLabels_ = [];\n this.parallelsLabels_ = [];\n }\n\n this.setMap(options.map !== undefined ? options.map : null);\n};\n\n\n/**\n * @param {number} lon Longitude.\n * @param {number} minLat Minimal latitude.\n * @param {number} maxLat Maximal latitude.\n * @param {number} squaredTolerance Squared tolerance.\n * @param {module:ol/extent~Extent} extent Extent.\n * @param {number} index Index.\n * @return {number} Index.\n * @private\n */\nGraticule.prototype.addMeridian_ = function(lon, minLat, maxLat, squaredTolerance, extent, index) {\n const lineString = this.getMeridian_(lon, minLat, maxLat, squaredTolerance, index);\n if (intersects(lineString.getExtent(), extent)) {\n if (this.meridiansLabels_) {\n const textPoint = this.getMeridianPoint_(lineString, extent, index);\n this.meridiansLabels_[index] = {\n geom: textPoint,\n text: this.lonLabelFormatter_(lon)\n };\n }\n this.meridians_[index++] = lineString;\n }\n return index;\n};\n\n/**\n * @param {module:ol/geom/LineString} lineString Meridian\n * @param {module:ol/extent~Extent} extent Extent.\n * @param {number} index Index.\n * @return {module:ol/geom/Point} Meridian point.\n * @private\n */\nGraticule.prototype.getMeridianPoint_ = function(lineString, extent, index) {\n const flatCoordinates = lineString.getFlatCoordinates();\n const clampedBottom = Math.max(extent[1], flatCoordinates[1]);\n const clampedTop = Math.min(extent[3], flatCoordinates[flatCoordinates.length - 1]);\n const lat = clamp(\n extent[1] + Math.abs(extent[1] - extent[3]) * this.lonLabelPosition_,\n clampedBottom, clampedTop);\n const coordinate = [flatCoordinates[0], lat];\n const point = this.meridiansLabels_[index] !== undefined ?\n this.meridiansLabels_[index].geom : new Point(null);\n point.setCoordinates(coordinate);\n return point;\n};\n\n\n/**\n * @param {number} lat Latitude.\n * @param {number} minLon Minimal longitude.\n * @param {number} maxLon Maximal longitude.\n * @param {number} squaredTolerance Squared tolerance.\n * @param {module:ol/extent~Extent} extent Extent.\n * @param {number} index Index.\n * @return {number} Index.\n * @private\n */\nGraticule.prototype.addParallel_ = function(lat, minLon, maxLon, squaredTolerance, extent, index) {\n const lineString = this.getParallel_(lat, minLon, maxLon, squaredTolerance, index);\n if (intersects(lineString.getExtent(), extent)) {\n if (this.parallelsLabels_) {\n const textPoint = this.getParallelPoint_(lineString, extent, index);\n this.parallelsLabels_[index] = {\n geom: textPoint,\n text: this.latLabelFormatter_(lat)\n };\n }\n this.parallels_[index++] = lineString;\n }\n return index;\n};\n\n\n/**\n * @param {module:ol/geom/LineString} lineString Parallels.\n * @param {module:ol/extent~Extent} extent Extent.\n * @param {number} index Index.\n * @return {module:ol/geom/Point} Parallel point.\n * @private\n */\nGraticule.prototype.getParallelPoint_ = function(lineString, extent, index) {\n const flatCoordinates = lineString.getFlatCoordinates();\n const clampedLeft = Math.max(extent[0], flatCoordinates[0]);\n const clampedRight = Math.min(extent[2], flatCoordinates[flatCoordinates.length - 2]);\n const lon = clamp(\n extent[0] + Math.abs(extent[0] - extent[2]) * this.latLabelPosition_,\n clampedLeft, clampedRight);\n const coordinate = [lon, flatCoordinates[1]];\n const point = this.parallelsLabels_[index] !== undefined ?\n this.parallelsLabels_[index].geom : new Point(null);\n point.setCoordinates(coordinate);\n return point;\n};\n\n\n/**\n * @param {module:ol/extent~Extent} extent Extent.\n * @param {module:ol/coordinate~Coordinate} center Center.\n * @param {number} resolution Resolution.\n * @param {number} squaredTolerance Squared tolerance.\n * @private\n */\nGraticule.prototype.createGraticule_ = function(extent, center, resolution, squaredTolerance) {\n\n const interval = this.getInterval_(resolution);\n if (interval == -1) {\n this.meridians_.length = this.parallels_.length = 0;\n if (this.meridiansLabels_) {\n this.meridiansLabels_.length = 0;\n }\n if (this.parallelsLabels_) {\n this.parallelsLabels_.length = 0;\n }\n return;\n }\n\n const centerLonLat = this.toLonLatTransform_(center);\n let centerLon = centerLonLat[0];\n let centerLat = centerLonLat[1];\n const maxLines = this.maxLines_;\n let cnt, idx, lat, lon;\n\n let validExtent = [\n Math.max(extent[0], this.minLonP_),\n Math.max(extent[1], this.minLatP_),\n Math.min(extent[2], this.maxLonP_),\n Math.min(extent[3], this.maxLatP_)\n ];\n\n validExtent = transformExtent(validExtent, this.projection_, 'EPSG:4326');\n const maxLat = validExtent[3];\n const maxLon = validExtent[2];\n const minLat = validExtent[1];\n const minLon = validExtent[0];\n\n // Create meridians\n\n centerLon = Math.floor(centerLon / interval) * interval;\n lon = clamp(centerLon, this.minLon_, this.maxLon_);\n\n idx = this.addMeridian_(lon, minLat, maxLat, squaredTolerance, extent, 0);\n\n cnt = 0;\n while (lon != this.minLon_ && cnt++ < maxLines) {\n lon = Math.max(lon - interval, this.minLon_);\n idx = this.addMeridian_(lon, minLat, maxLat, squaredTolerance, extent, idx);\n }\n\n lon = clamp(centerLon, this.minLon_, this.maxLon_);\n\n cnt = 0;\n while (lon != this.maxLon_ && cnt++ < maxLines) {\n lon = Math.min(lon + interval, this.maxLon_);\n idx = this.addMeridian_(lon, minLat, maxLat, squaredTolerance, extent, idx);\n }\n\n this.meridians_.length = idx;\n if (this.meridiansLabels_) {\n this.meridiansLabels_.length = idx;\n }\n\n // Create parallels\n\n centerLat = Math.floor(centerLat / interval) * interval;\n lat = clamp(centerLat, this.minLat_, this.maxLat_);\n\n idx = this.addParallel_(lat, minLon, maxLon, squaredTolerance, extent, 0);\n\n cnt = 0;\n while (lat != this.minLat_ && cnt++ < maxLines) {\n lat = Math.max(lat - interval, this.minLat_);\n idx = this.addParallel_(lat, minLon, maxLon, squaredTolerance, extent, idx);\n }\n\n lat = clamp(centerLat, this.minLat_, this.maxLat_);\n\n cnt = 0;\n while (lat != this.maxLat_ && cnt++ < maxLines) {\n lat = Math.min(lat + interval, this.maxLat_);\n idx = this.addParallel_(lat, minLon, maxLon, squaredTolerance, extent, idx);\n }\n\n this.parallels_.length = idx;\n if (this.parallelsLabels_) {\n this.parallelsLabels_.length = idx;\n }\n\n};\n\n\n/**\n * @param {number} resolution Resolution.\n * @return {number} The interval in degrees.\n * @private\n */\nGraticule.prototype.getInterval_ = function(resolution) {\n const centerLon = this.projectionCenterLonLat_[0];\n const centerLat = this.projectionCenterLonLat_[1];\n let interval = -1;\n const target = Math.pow(this.targetSize_ * resolution, 2);\n /** @type {Array.} **/\n const p1 = [];\n /** @type {Array.} **/\n const p2 = [];\n for (let i = 0, ii = INTERVALS.length; i < ii; ++i) {\n const delta = INTERVALS[i] / 2;\n p1[0] = centerLon - delta;\n p1[1] = centerLat - delta;\n p2[0] = centerLon + delta;\n p2[1] = centerLat + delta;\n this.fromLonLatTransform_(p1, p1);\n this.fromLonLatTransform_(p2, p2);\n const dist = Math.pow(p2[0] - p1[0], 2) + Math.pow(p2[1] - p1[1], 2);\n if (dist <= target) {\n break;\n }\n interval = INTERVALS[i];\n }\n return interval;\n};\n\n\n/**\n * Get the map associated with this graticule.\n * @return {module:ol/PluggableMap} The map.\n * @api\n */\nGraticule.prototype.getMap = function() {\n return this.map_;\n};\n\n\n/**\n * @param {number} lon Longitude.\n * @param {number} minLat Minimal latitude.\n * @param {number} maxLat Maximal latitude.\n * @param {number} squaredTolerance Squared tolerance.\n * @return {module:ol/geom/LineString} The meridian line string.\n * @param {number} index Index.\n * @private\n */\nGraticule.prototype.getMeridian_ = function(lon, minLat, maxLat, squaredTolerance, index) {\n const flatCoordinates = meridian(lon, minLat, maxLat, this.projection_, squaredTolerance);\n const lineString = this.meridians_[index] !== undefined ? this.meridians_[index] : new LineString(null);\n lineString.setFlatCoordinates(GeometryLayout.XY, flatCoordinates);\n return lineString;\n};\n\n\n/**\n * Get the list of meridians. Meridians are lines of equal longitude.\n * @return {Array.} The meridians.\n * @api\n */\nGraticule.prototype.getMeridians = function() {\n return this.meridians_;\n};\n\n\n/**\n * @param {number} lat Latitude.\n * @param {number} minLon Minimal longitude.\n * @param {number} maxLon Maximal longitude.\n * @param {number} squaredTolerance Squared tolerance.\n * @return {module:ol/geom/LineString} The parallel line string.\n * @param {number} index Index.\n * @private\n */\nGraticule.prototype.getParallel_ = function(lat, minLon, maxLon, squaredTolerance, index) {\n const flatCoordinates = parallel(lat, minLon, maxLon, this.projection_, squaredTolerance);\n const lineString = this.parallels_[index] !== undefined ? this.parallels_[index] : new LineString(null);\n lineString.setFlatCoordinates(GeometryLayout.XY, flatCoordinates);\n return lineString;\n};\n\n\n/**\n * Get the list of parallels. Parallels are lines of equal latitude.\n * @return {Array.} The parallels.\n * @api\n */\nGraticule.prototype.getParallels = function() {\n return this.parallels_;\n};\n\n\n/**\n * @param {module:ol/render/Event} e Event.\n * @private\n */\nGraticule.prototype.handlePostCompose_ = function(e) {\n const vectorContext = e.vectorContext;\n const frameState = e.frameState;\n const extent = frameState.extent;\n const viewState = frameState.viewState;\n const center = viewState.center;\n const projection = viewState.projection;\n const resolution = viewState.resolution;\n const pixelRatio = frameState.pixelRatio;\n const squaredTolerance =\n resolution * resolution / (4 * pixelRatio * pixelRatio);\n\n const updateProjectionInfo = !this.projection_ ||\n !equivalentProjection(this.projection_, projection);\n\n if (updateProjectionInfo) {\n this.updateProjectionInfo_(projection);\n }\n\n this.createGraticule_(extent, center, resolution, squaredTolerance);\n\n // Draw the lines\n vectorContext.setFillStrokeStyle(null, this.strokeStyle_);\n let i, l, line;\n for (i = 0, l = this.meridians_.length; i < l; ++i) {\n line = this.meridians_[i];\n vectorContext.drawGeometry(line);\n }\n for (i = 0, l = this.parallels_.length; i < l; ++i) {\n line = this.parallels_[i];\n vectorContext.drawGeometry(line);\n }\n let labelData;\n if (this.meridiansLabels_) {\n for (i = 0, l = this.meridiansLabels_.length; i < l; ++i) {\n labelData = this.meridiansLabels_[i];\n this.lonLabelStyle_.setText(labelData.text);\n vectorContext.setTextStyle(this.lonLabelStyle_);\n vectorContext.drawGeometry(labelData.geom);\n }\n }\n if (this.parallelsLabels_) {\n for (i = 0, l = this.parallelsLabels_.length; i < l; ++i) {\n labelData = this.parallelsLabels_[i];\n this.latLabelStyle_.setText(labelData.text);\n vectorContext.setTextStyle(this.latLabelStyle_);\n vectorContext.drawGeometry(labelData.geom);\n }\n }\n};\n\n\n/**\n * @param {module:ol/proj/Projection} projection Projection.\n * @private\n */\nGraticule.prototype.updateProjectionInfo_ = function(projection) {\n const epsg4326Projection = getProjection('EPSG:4326');\n\n const worldExtent = projection.getWorldExtent();\n const worldExtentP = transformExtent(worldExtent, epsg4326Projection, projection);\n\n this.maxLat_ = worldExtent[3];\n this.maxLon_ = worldExtent[2];\n this.minLat_ = worldExtent[1];\n this.minLon_ = worldExtent[0];\n\n this.maxLatP_ = worldExtentP[3];\n this.maxLonP_ = worldExtentP[2];\n this.minLatP_ = worldExtentP[1];\n this.minLonP_ = worldExtentP[0];\n\n this.fromLonLatTransform_ = getTransform(epsg4326Projection, projection);\n\n this.toLonLatTransform_ = getTransform(projection, epsg4326Projection);\n\n this.projectionCenterLonLat_ = this.toLonLatTransform_(getCenter(projection.getExtent()));\n\n this.projection_ = projection;\n};\n\n\n/**\n * Set the map for this graticule. The graticule will be rendered on the\n * provided map.\n * @param {module:ol/PluggableMap} map Map.\n * @api\n */\nGraticule.prototype.setMap = function(map) {\n if (this.map_) {\n unlistenByKey(this.postcomposeListenerKey_);\n this.postcomposeListenerKey_ = null;\n this.map_.render();\n }\n if (map) {\n this.postcomposeListenerKey_ = listen(map, RenderEventType.POSTCOMPOSE, this.handlePostCompose_, this);\n map.render();\n }\n this.map_ = map;\n};\nexport default Graticule;\n","/**\n * @module ol/ImageBase\n */\nimport {inherits} from './util.js';\nimport EventTarget from './events/EventTarget.js';\nimport EventType from './events/EventType.js';\n\n/**\n * @constructor\n * @abstract\n * @extends {module:ol/events/EventTarget}\n * @param {module:ol/extent~Extent} extent Extent.\n * @param {number|undefined} resolution Resolution.\n * @param {number} pixelRatio Pixel ratio.\n * @param {module:ol/ImageState} state State.\n */\nconst ImageBase = function(extent, resolution, pixelRatio, state) {\n\n EventTarget.call(this);\n\n /**\n * @protected\n * @type {module:ol/extent~Extent}\n */\n this.extent = extent;\n\n /**\n * @private\n * @type {number}\n */\n this.pixelRatio_ = pixelRatio;\n\n /**\n * @protected\n * @type {number|undefined}\n */\n this.resolution = resolution;\n\n /**\n * @protected\n * @type {module:ol/ImageState}\n */\n this.state = state;\n\n};\n\ninherits(ImageBase, EventTarget);\n\n\n/**\n * @protected\n */\nImageBase.prototype.changed = function() {\n this.dispatchEvent(EventType.CHANGE);\n};\n\n\n/**\n * @return {module:ol/extent~Extent} Extent.\n */\nImageBase.prototype.getExtent = function() {\n return this.extent;\n};\n\n\n/**\n * @abstract\n * @return {HTMLCanvasElement|Image|HTMLVideoElement} Image.\n */\nImageBase.prototype.getImage = function() {};\n\n\n/**\n * @return {number} PixelRatio.\n */\nImageBase.prototype.getPixelRatio = function() {\n return this.pixelRatio_;\n};\n\n\n/**\n * @return {number} Resolution.\n */\nImageBase.prototype.getResolution = function() {\n return /** @type {number} */ (this.resolution);\n};\n\n\n/**\n * @return {module:ol/ImageState} State.\n */\nImageBase.prototype.getState = function() {\n return this.state;\n};\n\n\n/**\n * Load not yet loaded URI.\n * @abstract\n */\nImageBase.prototype.load = function() {};\n\nexport default ImageBase;\n","/**\n * @module ol/Image\n */\nimport {inherits} from './util.js';\nimport ImageBase from './ImageBase.js';\nimport ImageState from './ImageState.js';\nimport {listenOnce, unlistenByKey} from './events.js';\nimport EventType from './events/EventType.js';\nimport {getHeight} from './extent.js';\n\n\n/**\n * A function that takes an {@link module:ol/Image~Image} for the image and a\n * `{string}` for the src as arguments. It is supposed to make it so the\n * underlying image {@link module:ol/Image~Image#getImage} is assigned the\n * content specified by the src. If not specified, the default is\n *\n * function(image, src) {\n * image.getImage().src = src;\n * }\n *\n * Providing a custom `imageLoadFunction` can be useful to load images with\n * post requests or - in general - through XHR requests, where the src of the\n * image element would be set to a data URI when the content is loaded.\n *\n * @typedef {function(module:ol/Image, string)} LoadFunction\n * @api\n */\n\n\n/**\n * @constructor\n * @extends {module:ol/ImageBase}\n * @param {module:ol/extent~Extent} extent Extent.\n * @param {number|undefined} resolution Resolution.\n * @param {number} pixelRatio Pixel ratio.\n * @param {string} src Image source URI.\n * @param {?string} crossOrigin Cross origin.\n * @param {module:ol/Image~LoadFunction} imageLoadFunction Image load function.\n */\nconst ImageWrapper = function(extent, resolution, pixelRatio, src, crossOrigin, imageLoadFunction) {\n\n ImageBase.call(this, extent, resolution, pixelRatio, ImageState.IDLE);\n\n /**\n * @private\n * @type {string}\n */\n this.src_ = src;\n\n /**\n * @private\n * @type {HTMLCanvasElement|Image|HTMLVideoElement}\n */\n this.image_ = new Image();\n if (crossOrigin !== null) {\n this.image_.crossOrigin = crossOrigin;\n }\n\n /**\n * @private\n * @type {Array.}\n */\n this.imageListenerKeys_ = null;\n\n /**\n * @protected\n * @type {module:ol/ImageState}\n */\n this.state = ImageState.IDLE;\n\n /**\n * @private\n * @type {module:ol/Image~LoadFunction}\n */\n this.imageLoadFunction_ = imageLoadFunction;\n\n};\n\ninherits(ImageWrapper, ImageBase);\n\n\n/**\n * @inheritDoc\n * @api\n */\nImageWrapper.prototype.getImage = function() {\n return this.image_;\n};\n\n\n/**\n * Tracks loading or read errors.\n *\n * @private\n */\nImageWrapper.prototype.handleImageError_ = function() {\n this.state = ImageState.ERROR;\n this.unlistenImage_();\n this.changed();\n};\n\n\n/**\n * Tracks successful image load.\n *\n * @private\n */\nImageWrapper.prototype.handleImageLoad_ = function() {\n if (this.resolution === undefined) {\n this.resolution = getHeight(this.extent) / this.image_.height;\n }\n this.state = ImageState.LOADED;\n this.unlistenImage_();\n this.changed();\n};\n\n\n/**\n * Load the image or retry if loading previously failed.\n * Loading is taken care of by the tile queue, and calling this method is\n * only needed for preloading or for reloading in case of an error.\n * @override\n * @api\n */\nImageWrapper.prototype.load = function() {\n if (this.state == ImageState.IDLE || this.state == ImageState.ERROR) {\n this.state = ImageState.LOADING;\n this.changed();\n this.imageListenerKeys_ = [\n listenOnce(this.image_, EventType.ERROR,\n this.handleImageError_, this),\n listenOnce(this.image_, EventType.LOAD,\n this.handleImageLoad_, this)\n ];\n this.imageLoadFunction_(this, this.src_);\n }\n};\n\n\n/**\n * @param {HTMLCanvasElement|Image|HTMLVideoElement} image Image.\n */\nImageWrapper.prototype.setImage = function(image) {\n this.image_ = image;\n};\n\n\n/**\n * Discards event handlers which listen for load completion or errors.\n *\n * @private\n */\nImageWrapper.prototype.unlistenImage_ = function() {\n this.imageListenerKeys_.forEach(unlistenByKey);\n this.imageListenerKeys_ = null;\n};\n\nexport default ImageWrapper;\n","/**\n * @module ol/TileState\n */\n\n/**\n * @enum {number}\n */\nexport default {\n IDLE: 0,\n LOADING: 1,\n LOADED: 2,\n ERROR: 3,\n EMPTY: 4,\n ABORT: 5\n};\n","/**\n * @module ol/easing\n */\n\n\n/**\n * Start slow and speed up.\n * @param {number} t Input between 0 and 1.\n * @return {number} Output between 0 and 1.\n * @api\n */\nexport function easeIn(t) {\n return Math.pow(t, 3);\n}\n\n\n/**\n * Start fast and slow down.\n * @param {number} t Input between 0 and 1.\n * @return {number} Output between 0 and 1.\n * @api\n */\nexport function easeOut(t) {\n return 1 - easeIn(1 - t);\n}\n\n\n/**\n * Start slow, speed up, and then slow down again.\n * @param {number} t Input between 0 and 1.\n * @return {number} Output between 0 and 1.\n * @api\n */\nexport function inAndOut(t) {\n return 3 * t * t - 2 * t * t * t;\n}\n\n\n/**\n * Maintain a constant speed over time.\n * @param {number} t Input between 0 and 1.\n * @return {number} Output between 0 and 1.\n * @api\n */\nexport function linear(t) {\n return t;\n}\n\n\n/**\n * Start slow, speed up, and at the very end slow down again. This has the\n * same general behavior as {@link module:ol/easing~inAndOut}, but the final\n * slowdown is delayed.\n * @param {number} t Input between 0 and 1.\n * @return {number} Output between 0 and 1.\n * @api\n */\nexport function upAndDown(t) {\n if (t < 0.5) {\n return inAndOut(2 * t);\n } else {\n return 1 - inAndOut(2 * (t - 0.5));\n }\n}\n","/**\n * @module ol/Tile\n */\nimport {inherits} from './util.js';\nimport TileState from './TileState.js';\nimport {easeIn} from './easing.js';\nimport EventTarget from './events/EventTarget.js';\nimport EventType from './events/EventType.js';\n\n\n/**\n * A function that takes an {@link module:ol/Tile} for the tile and a\n * `{string}` for the url as arguments.\n *\n * @typedef {function(module:ol/Tile, string)} LoadFunction\n * @api\n */\n\n/**\n * {@link module:ol/source/Tile~Tile} sources use a function of this type to get\n * the url that provides a tile for a given tile coordinate.\n *\n * This function takes an {@link module:ol/tilecoord~TileCoord} for the tile\n * coordinate, a `{number}` representing the pixel ratio and a\n * {@link module:ol/proj/Projection} for the projection as arguments\n * and returns a `{string}` representing the tile URL, or undefined if no tile\n * should be requested for the passed tile coordinate.\n *\n * @typedef {function(module:ol/tilecoord~TileCoord, number,\n * module:ol/proj/Projection): (string|undefined)} UrlFunction\n * @api\n */\n\n\n/**\n * @typedef {Object} Options\n * @property {number} [transition=250] A duration for tile opacity\n * transitions in milliseconds. A duration of 0 disables the opacity transition.\n * @api\n */\n\n\n/**\n * @classdesc\n * Base class for tiles.\n *\n * @constructor\n * @abstract\n * @extends {module:ol/events/EventTarget}\n * @param {module:ol/tilecoord~TileCoord} tileCoord Tile coordinate.\n * @param {module:ol/TileState} state State.\n * @param {module:ol/Tile~Options=} opt_options Tile options.\n */\nconst Tile = function(tileCoord, state, opt_options) {\n EventTarget.call(this);\n\n const options = opt_options ? opt_options : {};\n\n /**\n * @type {module:ol/tilecoord~TileCoord}\n */\n this.tileCoord = tileCoord;\n\n /**\n * @protected\n * @type {module:ol/TileState}\n */\n this.state = state;\n\n /**\n * An \"interim\" tile for this tile. The interim tile may be used while this\n * one is loading, for \"smooth\" transitions when changing params/dimensions\n * on the source.\n * @type {module:ol/Tile}\n */\n this.interimTile = null;\n\n /**\n * A key assigned to the tile. This is used by the tile source to determine\n * if this tile can effectively be used, or if a new tile should be created\n * and this one be used as an interim tile for this new tile.\n * @type {string}\n */\n this.key = '';\n\n /**\n * The duration for the opacity transition.\n * @type {number}\n */\n this.transition_ = options.transition === undefined ? 250 : options.transition;\n\n /**\n * Lookup of start times for rendering transitions. If the start time is\n * equal to -1, the transition is complete.\n * @type {Object.}\n */\n this.transitionStarts_ = {};\n\n};\n\ninherits(Tile, EventTarget);\n\n\n/**\n * @protected\n */\nTile.prototype.changed = function() {\n this.dispatchEvent(EventType.CHANGE);\n};\n\n\n/**\n * @return {string} Key.\n */\nTile.prototype.getKey = function() {\n return this.key + '/' + this.tileCoord;\n};\n\n/**\n * Get the interim tile most suitable for rendering using the chain of interim\n * tiles. This corresponds to the most recent tile that has been loaded, if no\n * such tile exists, the original tile is returned.\n * @return {!module:ol/Tile} Best tile for rendering.\n */\nTile.prototype.getInterimTile = function() {\n if (!this.interimTile) {\n //empty chain\n return this;\n }\n let tile = this.interimTile;\n\n // find the first loaded tile and return it. Since the chain is sorted in\n // decreasing order of creation time, there is no need to search the remainder\n // of the list (all those tiles correspond to older requests and will be\n // cleaned up by refreshInterimChain)\n do {\n if (tile.getState() == TileState.LOADED) {\n return tile;\n }\n tile = tile.interimTile;\n } while (tile);\n\n // we can not find a better tile\n return this;\n};\n\n/**\n * Goes through the chain of interim tiles and discards sections of the chain\n * that are no longer relevant.\n */\nTile.prototype.refreshInterimChain = function() {\n if (!this.interimTile) {\n return;\n }\n\n let tile = this.interimTile;\n let prev = this;\n\n do {\n if (tile.getState() == TileState.LOADED) {\n //we have a loaded tile, we can discard the rest of the list\n //we would could abort any LOADING tile request\n //older than this tile (i.e. any LOADING tile following this entry in the chain)\n tile.interimTile = null;\n break;\n } else if (tile.getState() == TileState.LOADING) {\n //keep this LOADING tile any loaded tiles later in the chain are\n //older than this tile, so we're still interested in the request\n prev = tile;\n } else if (tile.getState() == TileState.IDLE) {\n //the head of the list is the most current tile, we don't need\n //to start any other requests for this chain\n prev.interimTile = tile.interimTile;\n } else {\n prev = tile;\n }\n tile = prev.interimTile;\n } while (tile);\n};\n\n/**\n * Get the tile coordinate for this tile.\n * @return {module:ol/tilecoord~TileCoord} The tile coordinate.\n * @api\n */\nTile.prototype.getTileCoord = function() {\n return this.tileCoord;\n};\n\n\n/**\n * @return {module:ol/TileState} State.\n */\nTile.prototype.getState = function() {\n return this.state;\n};\n\n/**\n * @param {module:ol/TileState} state State.\n */\nTile.prototype.setState = function(state) {\n this.state = state;\n this.changed();\n};\n\n/**\n * Load the image or retry if loading previously failed.\n * Loading is taken care of by the tile queue, and calling this method is\n * only needed for preloading or for reloading in case of an error.\n * @abstract\n * @api\n */\nTile.prototype.load = function() {};\n\n/**\n * Get the alpha value for rendering.\n * @param {number} id An id for the renderer.\n * @param {number} time The render frame time.\n * @return {number} A number between 0 and 1.\n */\nTile.prototype.getAlpha = function(id, time) {\n if (!this.transition_) {\n return 1;\n }\n\n let start = this.transitionStarts_[id];\n if (!start) {\n start = time;\n this.transitionStarts_[id] = start;\n } else if (start === -1) {\n return 1;\n }\n\n const delta = time - start + (1000 / 60); // avoid rendering at 0\n if (delta >= this.transition_) {\n return 1;\n }\n return easeIn(delta / this.transition_);\n};\n\n/**\n * Determine if a tile is in an alpha transition. A tile is considered in\n * transition if tile.getAlpha() has not yet been called or has been called\n * and returned 1.\n * @param {number} id An id for the renderer.\n * @return {boolean} The tile is in transition.\n */\nTile.prototype.inTransition = function(id) {\n if (!this.transition_) {\n return false;\n }\n return this.transitionStarts_[id] !== -1;\n};\n\n/**\n * Mark a transition as complete.\n * @param {number} id An id for the renderer.\n */\nTile.prototype.endTransition = function(id) {\n if (this.transition_) {\n this.transitionStarts_[id] = -1;\n }\n};\nexport default Tile;\n","/**\n * @module ol/ImageTile\n */\nimport {inherits} from './util.js';\nimport Tile from './Tile.js';\nimport TileState from './TileState.js';\nimport {createCanvasContext2D} from './dom.js';\nimport {listenOnce, unlistenByKey} from './events.js';\nimport EventType from './events/EventType.js';\n\n/**\n * @typedef {function(new: module:ol/ImageTile, module:ol/tilecoord~TileCoord,\n * module:ol/TileState, string, ?string, module:ol/Tile~LoadFunction)} TileClass\n * @api\n */\n\n/**\n * @constructor\n * @extends {module:ol/Tile}\n * @param {module:ol/tilecoord~TileCoord} tileCoord Tile coordinate.\n * @param {module:ol/TileState} state State.\n * @param {string} src Image source URI.\n * @param {?string} crossOrigin Cross origin.\n * @param {module:ol/Tile~LoadFunction} tileLoadFunction Tile load function.\n * @param {module:ol/Tile~Options=} opt_options Tile options.\n */\nconst ImageTile = function(tileCoord, state, src, crossOrigin, tileLoadFunction, opt_options) {\n\n Tile.call(this, tileCoord, state, opt_options);\n\n /**\n * @private\n * @type {?string}\n */\n this.crossOrigin_ = crossOrigin;\n\n /**\n * Image URI\n *\n * @private\n * @type {string}\n */\n this.src_ = src;\n\n /**\n * @private\n * @type {Image|HTMLCanvasElement}\n */\n this.image_ = new Image();\n if (crossOrigin !== null) {\n this.image_.crossOrigin = crossOrigin;\n }\n\n /**\n * @private\n * @type {Array.}\n */\n this.imageListenerKeys_ = null;\n\n /**\n * @private\n * @type {module:ol/Tile~LoadFunction}\n */\n this.tileLoadFunction_ = tileLoadFunction;\n\n};\n\ninherits(ImageTile, Tile);\n\n\n/**\n * @inheritDoc\n */\nImageTile.prototype.disposeInternal = function() {\n if (this.state == TileState.LOADING) {\n this.unlistenImage_();\n this.image_ = getBlankImage();\n }\n if (this.interimTile) {\n this.interimTile.dispose();\n }\n this.state = TileState.ABORT;\n this.changed();\n Tile.prototype.disposeInternal.call(this);\n};\n\n\n/**\n * Get the HTML image element for this tile (may be a Canvas, Image, or Video).\n * @return {HTMLCanvasElement|HTMLImageElement|HTMLVideoElement} Image.\n * @api\n */\nImageTile.prototype.getImage = function() {\n return this.image_;\n};\n\n\n/**\n * @inheritDoc\n */\nImageTile.prototype.getKey = function() {\n return this.src_;\n};\n\n\n/**\n * Tracks loading or read errors.\n *\n * @private\n */\nImageTile.prototype.handleImageError_ = function() {\n this.state = TileState.ERROR;\n this.unlistenImage_();\n this.image_ = getBlankImage();\n this.changed();\n};\n\n\n/**\n * Tracks successful image load.\n *\n * @private\n */\nImageTile.prototype.handleImageLoad_ = function() {\n if (this.image_.naturalWidth && this.image_.naturalHeight) {\n this.state = TileState.LOADED;\n } else {\n this.state = TileState.EMPTY;\n }\n this.unlistenImage_();\n this.changed();\n};\n\n\n/**\n * @inheritDoc\n * @api\n */\nImageTile.prototype.load = function() {\n if (this.state == TileState.ERROR) {\n this.state = TileState.IDLE;\n this.image_ = new Image();\n if (this.crossOrigin_ !== null) {\n this.image_.crossOrigin = this.crossOrigin_;\n }\n }\n if (this.state == TileState.IDLE) {\n this.state = TileState.LOADING;\n this.changed();\n this.imageListenerKeys_ = [\n listenOnce(this.image_, EventType.ERROR,\n this.handleImageError_, this),\n listenOnce(this.image_, EventType.LOAD,\n this.handleImageLoad_, this)\n ];\n this.tileLoadFunction_(this, this.src_);\n }\n};\n\n\n/**\n * Discards event handlers which listen for load completion or errors.\n *\n * @private\n */\nImageTile.prototype.unlistenImage_ = function() {\n this.imageListenerKeys_.forEach(unlistenByKey);\n this.imageListenerKeys_ = null;\n};\n\n\n/**\n * Get a 1-pixel blank image.\n * @return {HTMLCanvasElement} Blank image.\n */\nfunction getBlankImage() {\n const ctx = createCanvasContext2D(1, 1);\n ctx.fillStyle = 'rgba(0,0,0,0)';\n ctx.fillRect(0, 0, 1, 1);\n return ctx.canvas;\n}\n\nexport default ImageTile;\n","/**\n * @module ol/Kinetic\n */\n\n/**\n * @classdesc\n * Implementation of inertial deceleration for map movement.\n *\n * @constructor\n * @param {number} decay Rate of decay (must be negative).\n * @param {number} minVelocity Minimum velocity (pixels/millisecond).\n * @param {number} delay Delay to consider to calculate the kinetic\n * initial values (milliseconds).\n * @struct\n * @api\n */\nconst Kinetic = function(decay, minVelocity, delay) {\n\n /**\n * @private\n * @type {number}\n */\n this.decay_ = decay;\n\n /**\n * @private\n * @type {number}\n */\n this.minVelocity_ = minVelocity;\n\n /**\n * @private\n * @type {number}\n */\n this.delay_ = delay;\n\n /**\n * @private\n * @type {Array.}\n */\n this.points_ = [];\n\n /**\n * @private\n * @type {number}\n */\n this.angle_ = 0;\n\n /**\n * @private\n * @type {number}\n */\n this.initialVelocity_ = 0;\n};\n\n\n/**\n * FIXME empty description for jsdoc\n */\nKinetic.prototype.begin = function() {\n this.points_.length = 0;\n this.angle_ = 0;\n this.initialVelocity_ = 0;\n};\n\n\n/**\n * @param {number} x X.\n * @param {number} y Y.\n */\nKinetic.prototype.update = function(x, y) {\n this.points_.push(x, y, Date.now());\n};\n\n\n/**\n * @return {boolean} Whether we should do kinetic animation.\n */\nKinetic.prototype.end = function() {\n if (this.points_.length < 6) {\n // at least 2 points are required (i.e. there must be at least 6 elements\n // in the array)\n return false;\n }\n const delay = Date.now() - this.delay_;\n const lastIndex = this.points_.length - 3;\n if (this.points_[lastIndex + 2] < delay) {\n // the last tracked point is too old, which means that the user stopped\n // panning before releasing the map\n return false;\n }\n\n // get the first point which still falls into the delay time\n let firstIndex = lastIndex - 3;\n while (firstIndex > 0 && this.points_[firstIndex + 2] > delay) {\n firstIndex -= 3;\n }\n\n const duration = this.points_[lastIndex + 2] - this.points_[firstIndex + 2];\n // we don't want a duration of 0 (divide by zero)\n // we also make sure the user panned for a duration of at least one frame\n // (1/60s) to compute sane displacement values\n if (duration < 1000 / 60) {\n return false;\n }\n\n const dx = this.points_[lastIndex] - this.points_[firstIndex];\n const dy = this.points_[lastIndex + 1] - this.points_[firstIndex + 1];\n this.angle_ = Math.atan2(dy, dx);\n this.initialVelocity_ = Math.sqrt(dx * dx + dy * dy) / duration;\n return this.initialVelocity_ > this.minVelocity_;\n};\n\n\n/**\n * @return {number} Total distance travelled (pixels).\n */\nKinetic.prototype.getDistance = function() {\n return (this.minVelocity_ - this.initialVelocity_) / this.decay_;\n};\n\n\n/**\n * @return {number} Angle of the kinetic panning animation (radians).\n */\nKinetic.prototype.getAngle = function() {\n return this.angle_;\n};\nexport default Kinetic;\n","/**\n * @module ol/MapEvent\n */\nimport {inherits} from './util.js';\nimport Event from './events/Event.js';\n\n/**\n * @classdesc\n * Events emitted as map events are instances of this type.\n * See {@link module:ol/Map~Map} for which events trigger a map event.\n *\n * @constructor\n * @extends {module:ol/events/Event}\n * @param {string} type Event type.\n * @param {module:ol/PluggableMap} map Map.\n * @param {?module:ol/PluggableMap~FrameState=} opt_frameState Frame state.\n */\nconst MapEvent = function(type, map, opt_frameState) {\n\n Event.call(this, type);\n\n /**\n * The map where the event occurred.\n * @type {module:ol/PluggableMap}\n * @api\n */\n this.map = map;\n\n /**\n * The frame state at the time of the event.\n * @type {?module:ol/PluggableMap~FrameState}\n * @api\n */\n this.frameState = opt_frameState !== undefined ? opt_frameState : null;\n\n};\n\ninherits(MapEvent, Event);\nexport default MapEvent;\n","/**\n * @module ol/MapBrowserEvent\n */\nimport {inherits} from './util.js';\nimport MapEvent from './MapEvent.js';\n\n/**\n * @classdesc\n * Events emitted as map browser events are instances of this type.\n * See {@link module:ol/Map~Map} for which events trigger a map browser event.\n *\n * @constructor\n * @extends {module:ol/MapEvent}\n * @param {string} type Event type.\n * @param {module:ol/PluggableMap} map Map.\n * @param {Event} browserEvent Browser event.\n * @param {boolean=} opt_dragging Is the map currently being dragged?\n * @param {?module:ol/PluggableMap~FrameState=} opt_frameState Frame state.\n */\nconst MapBrowserEvent = function(type, map, browserEvent, opt_dragging, opt_frameState) {\n\n MapEvent.call(this, type, map, opt_frameState);\n\n /**\n * The original browser event.\n * @const\n * @type {Event}\n * @api\n */\n this.originalEvent = browserEvent;\n\n /**\n * The map pixel relative to the viewport corresponding to the original browser event.\n * @type {module:ol~Pixel}\n * @api\n */\n this.pixel = map.getEventPixel(browserEvent);\n\n /**\n * The coordinate in view projection corresponding to the original browser event.\n * @type {module:ol/coordinate~Coordinate}\n * @api\n */\n this.coordinate = map.getCoordinateFromPixel(this.pixel);\n\n /**\n * Indicates if the map is currently being dragged. Only set for\n * `POINTERDRAG` and `POINTERMOVE` events. Default is `false`.\n *\n * @type {boolean}\n * @api\n */\n this.dragging = opt_dragging !== undefined ? opt_dragging : false;\n\n};\n\ninherits(MapBrowserEvent, MapEvent);\n\n\n/**\n * Prevents the default browser action.\n * @see https://developer.mozilla.org/en-US/docs/Web/API/event.preventDefault\n * @override\n * @api\n */\nMapBrowserEvent.prototype.preventDefault = function() {\n MapEvent.prototype.preventDefault.call(this);\n this.originalEvent.preventDefault();\n};\n\n\n/**\n * Prevents further propagation of the current event.\n * @see https://developer.mozilla.org/en-US/docs/Web/API/event.stopPropagation\n * @override\n * @api\n */\nMapBrowserEvent.prototype.stopPropagation = function() {\n MapEvent.prototype.stopPropagation.call(this);\n this.originalEvent.stopPropagation();\n};\nexport default MapBrowserEvent;\n","/**\n * @module ol/MapBrowserEventType\n */\nimport EventType from './events/EventType.js';\n\n/**\n * Constants for event names.\n * @enum {string}\n */\nexport default {\n\n /**\n * A true single click with no dragging and no double click. Note that this\n * event is delayed by 250 ms to ensure that it is not a double click.\n * @event module:ol/MapBrowserEvent~MapBrowserEvent#singleclick\n * @api\n */\n SINGLECLICK: 'singleclick',\n\n /**\n * A click with no dragging. A double click will fire two of this.\n * @event module:ol/MapBrowserEvent~MapBrowserEvent#click\n * @api\n */\n CLICK: EventType.CLICK,\n\n /**\n * A true double click, with no dragging.\n * @event module:ol/MapBrowserEvent~MapBrowserEvent#dblclick\n * @api\n */\n DBLCLICK: EventType.DBLCLICK,\n\n /**\n * Triggered when a pointer is dragged.\n * @event module:ol/MapBrowserEvent~MapBrowserEvent#pointerdrag\n * @api\n */\n POINTERDRAG: 'pointerdrag',\n\n /**\n * Triggered when a pointer is moved. Note that on touch devices this is\n * triggered when the map is panned, so is not the same as mousemove.\n * @event module:ol/MapBrowserEvent~MapBrowserEvent#pointermove\n * @api\n */\n POINTERMOVE: 'pointermove',\n\n POINTERDOWN: 'pointerdown',\n POINTERUP: 'pointerup',\n POINTEROVER: 'pointerover',\n POINTEROUT: 'pointerout',\n POINTERENTER: 'pointerenter',\n POINTERLEAVE: 'pointerleave',\n POINTERCANCEL: 'pointercancel'\n};\n","/**\n * @module ol/MapBrowserPointerEvent\n */\nimport {inherits} from './util.js';\nimport MapBrowserEvent from './MapBrowserEvent.js';\n\n/**\n * @constructor\n * @extends {module:ol/MapBrowserEvent}\n * @param {string} type Event type.\n * @param {module:ol/PluggableMap} map Map.\n * @param {module:ol/pointer/PointerEvent} pointerEvent Pointer\n * event.\n * @param {boolean=} opt_dragging Is the map currently being dragged?\n * @param {?module:ol/PluggableMap~FrameState=} opt_frameState Frame state.\n */\nconst MapBrowserPointerEvent = function(type, map, pointerEvent, opt_dragging,\n opt_frameState) {\n\n MapBrowserEvent.call(this, type, map, pointerEvent.originalEvent, opt_dragging,\n opt_frameState);\n\n /**\n * @const\n * @type {module:ol/pointer/PointerEvent}\n */\n this.pointerEvent = pointerEvent;\n\n};\n\ninherits(MapBrowserPointerEvent, MapBrowserEvent);\nexport default MapBrowserPointerEvent;\n","/**\n * @module ol/pointer/EventType\n */\n\n/**\n * Constants for event names.\n * @enum {string}\n */\nexport default {\n POINTERMOVE: 'pointermove',\n POINTERDOWN: 'pointerdown',\n POINTERUP: 'pointerup',\n POINTEROVER: 'pointerover',\n POINTEROUT: 'pointerout',\n POINTERENTER: 'pointerenter',\n POINTERLEAVE: 'pointerleave',\n POINTERCANCEL: 'pointercancel'\n};\n","/**\n * @module ol/pointer/EventSource\n */\n/**\n * @param {module:ol/pointer/PointerEventHandler} dispatcher Event handler.\n * @param {!Object.} mapping Event mapping.\n * @constructor\n */\nconst EventSource = function(dispatcher, mapping) {\n /**\n * @type {module:ol/pointer/PointerEventHandler}\n */\n this.dispatcher = dispatcher;\n\n /**\n * @private\n * @const\n * @type {!Object.}\n */\n this.mapping_ = mapping;\n};\n\n\n/**\n * List of events supported by this source.\n * @return {Array.} Event names\n */\nEventSource.prototype.getEvents = function() {\n return Object.keys(this.mapping_);\n};\n\n\n/**\n * Returns the handler that should handle a given event type.\n * @param {string} eventType The event type.\n * @return {function(Event)} Handler\n */\nEventSource.prototype.getHandlerForEvent = function(eventType) {\n return this.mapping_[eventType];\n};\nexport default EventSource;\n","/**\n * @module ol/pointer/MouseSource\n */\n// Based on https://github.com/Polymer/PointerEvents\n\n// Copyright (c) 2013 The Polymer Authors. All rights reserved.\n//\n// Redistribution and use in source and binary forms, with or without\n// modification, are permitted provided that the following conditions are\n// met:\n//\n// * Redistributions of source code must retain the above copyright\n// notice, this list of conditions and the following disclaimer.\n// * Redistributions in binary form must reproduce the above\n// copyright notice, this list of conditions and the following disclaimer\n// in the documentation and/or other materials provided with the\n// distribution.\n// * Neither the name of Google Inc. nor the names of its\n// contributors may be used to endorse or promote products derived from\n// this software without specific prior written permission.\n//\n// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n// \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\nimport {inherits} from '../util.js';\nimport EventSource from '../pointer/EventSource.js';\n\n/**\n * @param {module:ol/pointer/PointerEventHandler} dispatcher Event handler.\n * @constructor\n * @extends {module:ol/pointer/EventSource}\n */\nconst MouseSource = function(dispatcher) {\n const mapping = {\n 'mousedown': this.mousedown,\n 'mousemove': this.mousemove,\n 'mouseup': this.mouseup,\n 'mouseover': this.mouseover,\n 'mouseout': this.mouseout\n };\n EventSource.call(this, dispatcher, mapping);\n\n /**\n * @const\n * @type {!Object.}\n */\n this.pointerMap = dispatcher.pointerMap;\n\n /**\n * @const\n * @type {Array.}\n */\n this.lastTouches = [];\n};\n\ninherits(MouseSource, EventSource);\n\n\n/**\n * @type {number}\n */\nexport const POINTER_ID = 1;\n\n\n/**\n * @type {string}\n */\nexport const POINTER_TYPE = 'mouse';\n\n\n/**\n * Radius around touchend that swallows mouse events.\n *\n * @type {number}\n */\nconst DEDUP_DIST = 25;\n\n\n/**\n * Detect if a mouse event was simulated from a touch by\n * checking if previously there was a touch event at the\n * same position.\n *\n * FIXME - Known problem with the native Android browser on\n * Samsung GT-I9100 (Android 4.1.2):\n * In case the page is scrolled, this function does not work\n * correctly when a canvas is used (WebGL or canvas renderer).\n * Mouse listeners on canvas elements (for this browser), create\n * two mouse events: One 'good' and one 'bad' one (on other browsers or\n * when a div is used, there is only one event). For the 'bad' one,\n * clientX/clientY and also pageX/pageY are wrong when the page\n * is scrolled. Because of that, this function can not detect if\n * the events were simulated from a touch event. As result, a\n * pointer event at a wrong position is dispatched, which confuses\n * the map interactions.\n * It is unclear, how one can get the correct position for the event\n * or detect that the positions are invalid.\n *\n * @private\n * @param {Event} inEvent The in event.\n * @return {boolean} True, if the event was generated by a touch.\n */\nMouseSource.prototype.isEventSimulatedFromTouch_ = function(inEvent) {\n const lts = this.lastTouches;\n const x = inEvent.clientX;\n const y = inEvent.clientY;\n for (let i = 0, l = lts.length, t; i < l && (t = lts[i]); i++) {\n // simulated mouse events will be swallowed near a primary touchend\n const dx = Math.abs(x - t[0]);\n const dy = Math.abs(y - t[1]);\n if (dx <= DEDUP_DIST && dy <= DEDUP_DIST) {\n return true;\n }\n }\n return false;\n};\n\n\n/**\n * Creates a copy of the original event that will be used\n * for the fake pointer event.\n *\n * @param {Event} inEvent The in event.\n * @param {module:ol/pointer/PointerEventHandler} dispatcher Event handler.\n * @return {Object} The copied event.\n */\nfunction prepareEvent(inEvent, dispatcher) {\n const e = dispatcher.cloneEvent(inEvent, inEvent);\n\n // forward mouse preventDefault\n const pd = e.preventDefault;\n e.preventDefault = function() {\n inEvent.preventDefault();\n pd();\n };\n\n e.pointerId = POINTER_ID;\n e.isPrimary = true;\n e.pointerType = POINTER_TYPE;\n\n return e;\n}\n\n\n/**\n * Handler for `mousedown`.\n *\n * @param {Event} inEvent The in event.\n */\nMouseSource.prototype.mousedown = function(inEvent) {\n if (!this.isEventSimulatedFromTouch_(inEvent)) {\n // TODO(dfreedman) workaround for some elements not sending mouseup\n // http://crbug/149091\n if (POINTER_ID.toString() in this.pointerMap) {\n this.cancel(inEvent);\n }\n const e = prepareEvent(inEvent, this.dispatcher);\n this.pointerMap[POINTER_ID.toString()] = inEvent;\n this.dispatcher.down(e, inEvent);\n }\n};\n\n\n/**\n * Handler for `mousemove`.\n *\n * @param {Event} inEvent The in event.\n */\nMouseSource.prototype.mousemove = function(inEvent) {\n if (!this.isEventSimulatedFromTouch_(inEvent)) {\n const e = prepareEvent(inEvent, this.dispatcher);\n this.dispatcher.move(e, inEvent);\n }\n};\n\n\n/**\n * Handler for `mouseup`.\n *\n * @param {Event} inEvent The in event.\n */\nMouseSource.prototype.mouseup = function(inEvent) {\n if (!this.isEventSimulatedFromTouch_(inEvent)) {\n const p = this.pointerMap[POINTER_ID.toString()];\n\n if (p && p.button === inEvent.button) {\n const e = prepareEvent(inEvent, this.dispatcher);\n this.dispatcher.up(e, inEvent);\n this.cleanupMouse();\n }\n }\n};\n\n\n/**\n * Handler for `mouseover`.\n *\n * @param {Event} inEvent The in event.\n */\nMouseSource.prototype.mouseover = function(inEvent) {\n if (!this.isEventSimulatedFromTouch_(inEvent)) {\n const e = prepareEvent(inEvent, this.dispatcher);\n this.dispatcher.enterOver(e, inEvent);\n }\n};\n\n\n/**\n * Handler for `mouseout`.\n *\n * @param {Event} inEvent The in event.\n */\nMouseSource.prototype.mouseout = function(inEvent) {\n if (!this.isEventSimulatedFromTouch_(inEvent)) {\n const e = prepareEvent(inEvent, this.dispatcher);\n this.dispatcher.leaveOut(e, inEvent);\n }\n};\n\n\n/**\n * Dispatches a `pointercancel` event.\n *\n * @param {Event} inEvent The in event.\n */\nMouseSource.prototype.cancel = function(inEvent) {\n const e = prepareEvent(inEvent, this.dispatcher);\n this.dispatcher.cancel(e, inEvent);\n this.cleanupMouse();\n};\n\n\n/**\n * Remove the mouse from the list of active pointers.\n */\nMouseSource.prototype.cleanupMouse = function() {\n delete this.pointerMap[POINTER_ID.toString()];\n};\nexport default MouseSource;\n","/**\n * @module ol/pointer/MsSource\n */\n// Based on https://github.com/Polymer/PointerEvents\n\n// Copyright (c) 2013 The Polymer Authors. All rights reserved.\n//\n// Redistribution and use in source and binary forms, with or without\n// modification, are permitted provided that the following conditions are\n// met:\n//\n// * Redistributions of source code must retain the above copyright\n// notice, this list of conditions and the following disclaimer.\n// * Redistributions in binary form must reproduce the above\n// copyright notice, this list of conditions and the following disclaimer\n// in the documentation and/or other materials provided with the\n// distribution.\n// * Neither the name of Google Inc. nor the names of its\n// contributors may be used to endorse or promote products derived from\n// this software without specific prior written permission.\n//\n// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n// \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\nimport {inherits} from '../util.js';\nimport EventSource from '../pointer/EventSource.js';\n\n/**\n * @param {module:ol/pointer/PointerEventHandler} dispatcher Event handler.\n * @constructor\n * @extends {module:ol/pointer/EventSource}\n */\nconst MsSource = function(dispatcher) {\n const mapping = {\n 'MSPointerDown': this.msPointerDown,\n 'MSPointerMove': this.msPointerMove,\n 'MSPointerUp': this.msPointerUp,\n 'MSPointerOut': this.msPointerOut,\n 'MSPointerOver': this.msPointerOver,\n 'MSPointerCancel': this.msPointerCancel,\n 'MSGotPointerCapture': this.msGotPointerCapture,\n 'MSLostPointerCapture': this.msLostPointerCapture\n };\n EventSource.call(this, dispatcher, mapping);\n\n /**\n * @const\n * @type {!Object.}\n */\n this.pointerMap = dispatcher.pointerMap;\n};\n\ninherits(MsSource, EventSource);\n\n/**\n * @const\n * @type {Array.}\n */\nconst POINTER_TYPES = [\n '',\n 'unavailable',\n 'touch',\n 'pen',\n 'mouse'\n];\n\n\n/**\n * Creates a copy of the original event that will be used\n * for the fake pointer event.\n *\n * @private\n * @param {MSPointerEvent} inEvent The in event.\n * @return {Object} The copied event.\n */\nMsSource.prototype.prepareEvent_ = function(inEvent) {\n let e = inEvent;\n if (typeof inEvent.pointerType === 'number') {\n e = this.dispatcher.cloneEvent(inEvent, inEvent);\n e.pointerType = POINTER_TYPES[inEvent.pointerType];\n }\n\n return e;\n};\n\n\n/**\n * Remove this pointer from the list of active pointers.\n * @param {number} pointerId Pointer identifier.\n */\nMsSource.prototype.cleanup = function(pointerId) {\n delete this.pointerMap[pointerId.toString()];\n};\n\n\n/**\n * Handler for `msPointerDown`.\n *\n * @param {MSPointerEvent} inEvent The in event.\n */\nMsSource.prototype.msPointerDown = function(inEvent) {\n this.pointerMap[inEvent.pointerId.toString()] = inEvent;\n const e = this.prepareEvent_(inEvent);\n this.dispatcher.down(e, inEvent);\n};\n\n\n/**\n * Handler for `msPointerMove`.\n *\n * @param {MSPointerEvent} inEvent The in event.\n */\nMsSource.prototype.msPointerMove = function(inEvent) {\n const e = this.prepareEvent_(inEvent);\n this.dispatcher.move(e, inEvent);\n};\n\n\n/**\n * Handler for `msPointerUp`.\n *\n * @param {MSPointerEvent} inEvent The in event.\n */\nMsSource.prototype.msPointerUp = function(inEvent) {\n const e = this.prepareEvent_(inEvent);\n this.dispatcher.up(e, inEvent);\n this.cleanup(inEvent.pointerId);\n};\n\n\n/**\n * Handler for `msPointerOut`.\n *\n * @param {MSPointerEvent} inEvent The in event.\n */\nMsSource.prototype.msPointerOut = function(inEvent) {\n const e = this.prepareEvent_(inEvent);\n this.dispatcher.leaveOut(e, inEvent);\n};\n\n\n/**\n * Handler for `msPointerOver`.\n *\n * @param {MSPointerEvent} inEvent The in event.\n */\nMsSource.prototype.msPointerOver = function(inEvent) {\n const e = this.prepareEvent_(inEvent);\n this.dispatcher.enterOver(e, inEvent);\n};\n\n\n/**\n * Handler for `msPointerCancel`.\n *\n * @param {MSPointerEvent} inEvent The in event.\n */\nMsSource.prototype.msPointerCancel = function(inEvent) {\n const e = this.prepareEvent_(inEvent);\n this.dispatcher.cancel(e, inEvent);\n this.cleanup(inEvent.pointerId);\n};\n\n\n/**\n * Handler for `msLostPointerCapture`.\n *\n * @param {MSPointerEvent} inEvent The in event.\n */\nMsSource.prototype.msLostPointerCapture = function(inEvent) {\n const e = this.dispatcher.makeEvent('lostpointercapture', inEvent, inEvent);\n this.dispatcher.dispatchEvent(e);\n};\n\n\n/**\n * Handler for `msGotPointerCapture`.\n *\n * @param {MSPointerEvent} inEvent The in event.\n */\nMsSource.prototype.msGotPointerCapture = function(inEvent) {\n const e = this.dispatcher.makeEvent('gotpointercapture', inEvent, inEvent);\n this.dispatcher.dispatchEvent(e);\n};\nexport default MsSource;\n","/**\n * @module ol/pointer/NativeSource\n */\n// Based on https://github.com/Polymer/PointerEvents\n\n// Copyright (c) 2013 The Polymer Authors. All rights reserved.\n//\n// Redistribution and use in source and binary forms, with or without\n// modification, are permitted provided that the following conditions are\n// met:\n//\n// * Redistributions of source code must retain the above copyright\n// notice, this list of conditions and the following disclaimer.\n// * Redistributions in binary form must reproduce the above\n// copyright notice, this list of conditions and the following disclaimer\n// in the documentation and/or other materials provided with the\n// distribution.\n// * Neither the name of Google Inc. nor the names of its\n// contributors may be used to endorse or promote products derived from\n// this software without specific prior written permission.\n//\n// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n// \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\nimport {inherits} from '../util.js';\nimport EventSource from '../pointer/EventSource.js';\n\n/**\n * @param {module:ol/pointer/PointerEventHandler} dispatcher Event handler.\n * @constructor\n * @extends {module:ol/pointer/EventSource}\n */\nconst NativeSource = function(dispatcher) {\n const mapping = {\n 'pointerdown': this.pointerDown,\n 'pointermove': this.pointerMove,\n 'pointerup': this.pointerUp,\n 'pointerout': this.pointerOut,\n 'pointerover': this.pointerOver,\n 'pointercancel': this.pointerCancel,\n 'gotpointercapture': this.gotPointerCapture,\n 'lostpointercapture': this.lostPointerCapture\n };\n EventSource.call(this, dispatcher, mapping);\n};\n\ninherits(NativeSource, EventSource);\n\n\n/**\n * Handler for `pointerdown`.\n *\n * @param {Event} inEvent The in event.\n */\nNativeSource.prototype.pointerDown = function(inEvent) {\n this.dispatcher.fireNativeEvent(inEvent);\n};\n\n\n/**\n * Handler for `pointermove`.\n *\n * @param {Event} inEvent The in event.\n */\nNativeSource.prototype.pointerMove = function(inEvent) {\n this.dispatcher.fireNativeEvent(inEvent);\n};\n\n\n/**\n * Handler for `pointerup`.\n *\n * @param {Event} inEvent The in event.\n */\nNativeSource.prototype.pointerUp = function(inEvent) {\n this.dispatcher.fireNativeEvent(inEvent);\n};\n\n\n/**\n * Handler for `pointerout`.\n *\n * @param {Event} inEvent The in event.\n */\nNativeSource.prototype.pointerOut = function(inEvent) {\n this.dispatcher.fireNativeEvent(inEvent);\n};\n\n\n/**\n * Handler for `pointerover`.\n *\n * @param {Event} inEvent The in event.\n */\nNativeSource.prototype.pointerOver = function(inEvent) {\n this.dispatcher.fireNativeEvent(inEvent);\n};\n\n\n/**\n * Handler for `pointercancel`.\n *\n * @param {Event} inEvent The in event.\n */\nNativeSource.prototype.pointerCancel = function(inEvent) {\n this.dispatcher.fireNativeEvent(inEvent);\n};\n\n\n/**\n * Handler for `lostpointercapture`.\n *\n * @param {Event} inEvent The in event.\n */\nNativeSource.prototype.lostPointerCapture = function(inEvent) {\n this.dispatcher.fireNativeEvent(inEvent);\n};\n\n\n/**\n * Handler for `gotpointercapture`.\n *\n * @param {Event} inEvent The in event.\n */\nNativeSource.prototype.gotPointerCapture = function(inEvent) {\n this.dispatcher.fireNativeEvent(inEvent);\n};\nexport default NativeSource;\n","/**\n * @module ol/pointer/PointerEvent\n */\n// Based on https://github.com/Polymer/PointerEvents\n\n// Copyright (c) 2013 The Polymer Authors. All rights reserved.\n//\n// Redistribution and use in source and binary forms, with or without\n// modification, are permitted provided that the following conditions are\n// met:\n//\n// * Redistributions of source code must retain the above copyright\n// notice, this list of conditions and the following disclaimer.\n// * Redistributions in binary form must reproduce the above\n// copyright notice, this list of conditions and the following disclaimer\n// in the documentation and/or other materials provided with the\n// distribution.\n// * Neither the name of Google Inc. nor the names of its\n// contributors may be used to endorse or promote products derived from\n// this software without specific prior written permission.\n//\n// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n// \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\nimport {inherits} from '../util.js';\nimport Event from '../events/Event.js';\n\n/**\n * A class for pointer events.\n *\n * This class is used as an abstraction for mouse events,\n * touch events and even native pointer events.\n *\n * @constructor\n * @extends {module:ol/events/Event}\n * @param {string} type The type of the event to create.\n * @param {Event} originalEvent The event.\n * @param {Object.=} opt_eventDict An optional dictionary of\n * initial event properties.\n */\nconst PointerEvent = function(type, originalEvent, opt_eventDict) {\n Event.call(this, type);\n\n /**\n * @const\n * @type {Event}\n */\n this.originalEvent = originalEvent;\n\n const eventDict = opt_eventDict ? opt_eventDict : {};\n\n /**\n * @type {number}\n */\n this.buttons = this.getButtons_(eventDict);\n\n /**\n * @type {number}\n */\n this.pressure = this.getPressure_(eventDict, this.buttons);\n\n // MouseEvent related properties\n\n /**\n * @type {boolean}\n */\n this.bubbles = 'bubbles' in eventDict ? eventDict['bubbles'] : false;\n\n /**\n * @type {boolean}\n */\n this.cancelable = 'cancelable' in eventDict ? eventDict['cancelable'] : false;\n\n /**\n * @type {Object}\n */\n this.view = 'view' in eventDict ? eventDict['view'] : null;\n\n /**\n * @type {number}\n */\n this.detail = 'detail' in eventDict ? eventDict['detail'] : null;\n\n /**\n * @type {number}\n */\n this.screenX = 'screenX' in eventDict ? eventDict['screenX'] : 0;\n\n /**\n * @type {number}\n */\n this.screenY = 'screenY' in eventDict ? eventDict['screenY'] : 0;\n\n /**\n * @type {number}\n */\n this.clientX = 'clientX' in eventDict ? eventDict['clientX'] : 0;\n\n /**\n * @type {number}\n */\n this.clientY = 'clientY' in eventDict ? eventDict['clientY'] : 0;\n\n /**\n * @type {boolean}\n */\n this.ctrlKey = 'ctrlKey' in eventDict ? eventDict['ctrlKey'] : false;\n\n /**\n * @type {boolean}\n */\n this.altKey = 'altKey' in eventDict ? eventDict['altKey'] : false;\n\n /**\n * @type {boolean}\n */\n this.shiftKey = 'shiftKey' in eventDict ? eventDict['shiftKey'] : false;\n\n /**\n * @type {boolean}\n */\n this.metaKey = 'metaKey' in eventDict ? eventDict['metaKey'] : false;\n\n /**\n * @type {number}\n */\n this.button = 'button' in eventDict ? eventDict['button'] : 0;\n\n /**\n * @type {Node}\n */\n this.relatedTarget = 'relatedTarget' in eventDict ?\n eventDict['relatedTarget'] : null;\n\n // PointerEvent related properties\n\n /**\n * @const\n * @type {number}\n */\n this.pointerId = 'pointerId' in eventDict ? eventDict['pointerId'] : 0;\n\n /**\n * @type {number}\n */\n this.width = 'width' in eventDict ? eventDict['width'] : 0;\n\n /**\n * @type {number}\n */\n this.height = 'height' in eventDict ? eventDict['height'] : 0;\n\n /**\n * @type {number}\n */\n this.tiltX = 'tiltX' in eventDict ? eventDict['tiltX'] : 0;\n\n /**\n * @type {number}\n */\n this.tiltY = 'tiltY' in eventDict ? eventDict['tiltY'] : 0;\n\n /**\n * @type {string}\n */\n this.pointerType = 'pointerType' in eventDict ? eventDict['pointerType'] : '';\n\n /**\n * @type {number}\n */\n this.hwTimestamp = 'hwTimestamp' in eventDict ? eventDict['hwTimestamp'] : 0;\n\n /**\n * @type {boolean}\n */\n this.isPrimary = 'isPrimary' in eventDict ? eventDict['isPrimary'] : false;\n\n // keep the semantics of preventDefault\n if (originalEvent.preventDefault) {\n this.preventDefault = function() {\n originalEvent.preventDefault();\n };\n }\n};\n\ninherits(PointerEvent, Event);\n\n\n/**\n * Is the `buttons` property supported?\n * @type {boolean}\n */\nlet HAS_BUTTONS = false;\n\n\n/**\n * @private\n * @param {Object.} eventDict The event dictionary.\n * @return {number} Button indicator.\n */\nPointerEvent.prototype.getButtons_ = function(eventDict) {\n // According to the w3c spec,\n // http://www.w3.org/TR/DOM-Level-3-Events/#events-MouseEvent-button\n // MouseEvent.button == 0 can mean either no mouse button depressed, or the\n // left mouse button depressed.\n //\n // As of now, the only way to distinguish between the two states of\n // MouseEvent.button is by using the deprecated MouseEvent.which property, as\n // this maps mouse buttons to positive integers > 0, and uses 0 to mean that\n // no mouse button is held.\n //\n // MouseEvent.which is derived from MouseEvent.button at MouseEvent creation,\n // but initMouseEvent does not expose an argument with which to set\n // MouseEvent.which. Calling initMouseEvent with a buttonArg of 0 will set\n // MouseEvent.button == 0 and MouseEvent.which == 1, breaking the expectations\n // of app developers.\n //\n // The only way to propagate the correct state of MouseEvent.which and\n // MouseEvent.button to a new MouseEvent.button == 0 and MouseEvent.which == 0\n // is to call initMouseEvent with a buttonArg value of -1.\n //\n // This is fixed with DOM Level 4's use of buttons\n let buttons;\n if (eventDict.buttons || HAS_BUTTONS) {\n buttons = eventDict.buttons;\n } else {\n switch (eventDict.which) {\n case 1: buttons = 1; break;\n case 2: buttons = 4; break;\n case 3: buttons = 2; break;\n default: buttons = 0;\n }\n }\n return buttons;\n};\n\n\n/**\n * @private\n * @param {Object.} eventDict The event dictionary.\n * @param {number} buttons Button indicator.\n * @return {number} The pressure.\n */\nPointerEvent.prototype.getPressure_ = function(eventDict, buttons) {\n // Spec requires that pointers without pressure specified use 0.5 for down\n // state and 0 for up state.\n let pressure = 0;\n if (eventDict.pressure) {\n pressure = eventDict.pressure;\n } else {\n pressure = buttons ? 0.5 : 0;\n }\n return pressure;\n};\n\n\n/**\n * Checks if the `buttons` property is supported.\n */\n(function() {\n try {\n const ev = new MouseEvent('click', {buttons: 1});\n HAS_BUTTONS = ev.buttons === 1;\n } catch (e) {\n // pass\n }\n})();\nexport default PointerEvent;\n","/**\n * @module ol/pointer/TouchSource\n */\n// Based on https://github.com/Polymer/PointerEvents\n\n// Copyright (c) 2013 The Polymer Authors. All rights reserved.\n//\n// Redistribution and use in source and binary forms, with or without\n// modification, are permitted provided that the following conditions are\n// met:\n//\n// * Redistributions of source code must retain the above copyright\n// notice, this list of conditions and the following disclaimer.\n// * Redistributions in binary form must reproduce the above\n// copyright notice, this list of conditions and the following disclaimer\n// in the documentation and/or other materials provided with the\n// distribution.\n// * Neither the name of Google Inc. nor the names of its\n// contributors may be used to endorse or promote products derived from\n// this software without specific prior written permission.\n//\n// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n// \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\nimport {inherits} from '../util.js';\nimport {remove} from '../array.js';\nimport EventSource from '../pointer/EventSource.js';\nimport {POINTER_ID} from '../pointer/MouseSource.js';\n\n\n/**\n * @constructor\n * @param {module:ol/pointer/PointerEventHandler} dispatcher The event handler.\n * @param {module:ol/pointer/MouseSource} mouseSource Mouse source.\n * @extends {module:ol/pointer/EventSource}\n */\nconst TouchSource = function(dispatcher, mouseSource) {\n const mapping = {\n 'touchstart': this.touchstart,\n 'touchmove': this.touchmove,\n 'touchend': this.touchend,\n 'touchcancel': this.touchcancel\n };\n EventSource.call(this, dispatcher, mapping);\n\n /**\n * @const\n * @type {!Object.}\n */\n this.pointerMap = dispatcher.pointerMap;\n\n /**\n * @const\n * @type {module:ol/pointer/MouseSource}\n */\n this.mouseSource = mouseSource;\n\n /**\n * @private\n * @type {number|undefined}\n */\n this.firstTouchId_ = undefined;\n\n /**\n * @private\n * @type {number}\n */\n this.clickCount_ = 0;\n\n /**\n * @private\n * @type {number|undefined}\n */\n this.resetId_ = undefined;\n\n /**\n * Mouse event timeout: This should be long enough to\n * ignore compat mouse events made by touch.\n * @private\n * @type {number}\n */\n this.dedupTimeout_ = 2500;\n};\n\ninherits(TouchSource, EventSource);\n\n\n/**\n * @type {number}\n */\nconst CLICK_COUNT_TIMEOUT = 200;\n\n\n/**\n * @type {string}\n */\nconst POINTER_TYPE = 'touch';\n\n/**\n * @private\n * @param {Touch} inTouch The in touch.\n * @return {boolean} True, if this is the primary touch.\n */\nTouchSource.prototype.isPrimaryTouch_ = function(inTouch) {\n return this.firstTouchId_ === inTouch.identifier;\n};\n\n\n/**\n * Set primary touch if there are no pointers, or the only pointer is the mouse.\n * @param {Touch} inTouch The in touch.\n * @private\n */\nTouchSource.prototype.setPrimaryTouch_ = function(inTouch) {\n const count = Object.keys(this.pointerMap).length;\n if (count === 0 || (count === 1 && POINTER_ID.toString() in this.pointerMap)) {\n this.firstTouchId_ = inTouch.identifier;\n this.cancelResetClickCount_();\n }\n};\n\n\n/**\n * @private\n * @param {Object} inPointer The in pointer object.\n */\nTouchSource.prototype.removePrimaryPointer_ = function(inPointer) {\n if (inPointer.isPrimary) {\n this.firstTouchId_ = undefined;\n this.resetClickCount_();\n }\n};\n\n\n/**\n * @private\n */\nTouchSource.prototype.resetClickCount_ = function() {\n this.resetId_ = setTimeout(\n this.resetClickCountHandler_.bind(this),\n CLICK_COUNT_TIMEOUT);\n};\n\n\n/**\n * @private\n */\nTouchSource.prototype.resetClickCountHandler_ = function() {\n this.clickCount_ = 0;\n this.resetId_ = undefined;\n};\n\n\n/**\n * @private\n */\nTouchSource.prototype.cancelResetClickCount_ = function() {\n if (this.resetId_ !== undefined) {\n clearTimeout(this.resetId_);\n }\n};\n\n\n/**\n * @private\n * @param {Event} browserEvent Browser event\n * @param {Touch} inTouch Touch event\n * @return {Object} A pointer object.\n */\nTouchSource.prototype.touchToPointer_ = function(browserEvent, inTouch) {\n const e = this.dispatcher.cloneEvent(browserEvent, inTouch);\n // Spec specifies that pointerId 1 is reserved for Mouse.\n // Touch identifiers can start at 0.\n // Add 2 to the touch identifier for compatibility.\n e.pointerId = inTouch.identifier + 2;\n // TODO: check if this is necessary?\n //e.target = findTarget(e);\n e.bubbles = true;\n e.cancelable = true;\n e.detail = this.clickCount_;\n e.button = 0;\n e.buttons = 1;\n e.width = inTouch.webkitRadiusX || inTouch.radiusX || 0;\n e.height = inTouch.webkitRadiusY || inTouch.radiusY || 0;\n e.pressure = inTouch.webkitForce || inTouch.force || 0.5;\n e.isPrimary = this.isPrimaryTouch_(inTouch);\n e.pointerType = POINTER_TYPE;\n\n // make sure that the properties that are different for\n // each `Touch` object are not copied from the BrowserEvent object\n e.clientX = inTouch.clientX;\n e.clientY = inTouch.clientY;\n e.screenX = inTouch.screenX;\n e.screenY = inTouch.screenY;\n\n return e;\n};\n\n\n/**\n * @private\n * @param {Event} inEvent Touch event\n * @param {function(Event, Object)} inFunction In function.\n */\nTouchSource.prototype.processTouches_ = function(inEvent, inFunction) {\n const touches = Array.prototype.slice.call(inEvent.changedTouches);\n const count = touches.length;\n function preventDefault() {\n inEvent.preventDefault();\n }\n for (let i = 0; i < count; ++i) {\n const pointer = this.touchToPointer_(inEvent, touches[i]);\n // forward touch preventDefaults\n pointer.preventDefault = preventDefault;\n inFunction.call(this, inEvent, pointer);\n }\n};\n\n\n/**\n * @private\n * @param {TouchList} touchList The touch list.\n * @param {number} searchId Search identifier.\n * @return {boolean} True, if the `Touch` with the given id is in the list.\n */\nTouchSource.prototype.findTouch_ = function(touchList, searchId) {\n const l = touchList.length;\n for (let i = 0; i < l; i++) {\n const touch = touchList[i];\n if (touch.identifier === searchId) {\n return true;\n }\n }\n return false;\n};\n\n\n/**\n * In some instances, a touchstart can happen without a touchend. This\n * leaves the pointermap in a broken state.\n * Therefore, on every touchstart, we remove the touches that did not fire a\n * touchend event.\n * To keep state globally consistent, we fire a pointercancel for\n * this \"abandoned\" touch\n *\n * @private\n * @param {Event} inEvent The in event.\n */\nTouchSource.prototype.vacuumTouches_ = function(inEvent) {\n const touchList = inEvent.touches;\n // pointerMap.getCount() should be < touchList.length here,\n // as the touchstart has not been processed yet.\n const keys = Object.keys(this.pointerMap);\n const count = keys.length;\n if (count >= touchList.length) {\n const d = [];\n for (let i = 0; i < count; ++i) {\n const key = keys[i];\n const value = this.pointerMap[key];\n // Never remove pointerId == 1, which is mouse.\n // Touch identifiers are 2 smaller than their pointerId, which is the\n // index in pointermap.\n if (key != POINTER_ID && !this.findTouch_(touchList, key - 2)) {\n d.push(value.out);\n }\n }\n for (let i = 0; i < d.length; ++i) {\n this.cancelOut_(inEvent, d[i]);\n }\n }\n};\n\n\n/**\n * Handler for `touchstart`, triggers `pointerover`,\n * `pointerenter` and `pointerdown` events.\n *\n * @param {Event} inEvent The in event.\n */\nTouchSource.prototype.touchstart = function(inEvent) {\n this.vacuumTouches_(inEvent);\n this.setPrimaryTouch_(inEvent.changedTouches[0]);\n this.dedupSynthMouse_(inEvent);\n this.clickCount_++;\n this.processTouches_(inEvent, this.overDown_);\n};\n\n\n/**\n * @private\n * @param {Event} browserEvent The event.\n * @param {Object} inPointer The in pointer object.\n */\nTouchSource.prototype.overDown_ = function(browserEvent, inPointer) {\n this.pointerMap[inPointer.pointerId] = {\n target: inPointer.target,\n out: inPointer,\n outTarget: inPointer.target\n };\n this.dispatcher.over(inPointer, browserEvent);\n this.dispatcher.enter(inPointer, browserEvent);\n this.dispatcher.down(inPointer, browserEvent);\n};\n\n\n/**\n * Handler for `touchmove`.\n *\n * @param {Event} inEvent The in event.\n */\nTouchSource.prototype.touchmove = function(inEvent) {\n inEvent.preventDefault();\n this.processTouches_(inEvent, this.moveOverOut_);\n};\n\n\n/**\n * @private\n * @param {Event} browserEvent The event.\n * @param {Object} inPointer The in pointer.\n */\nTouchSource.prototype.moveOverOut_ = function(browserEvent, inPointer) {\n const event = inPointer;\n const pointer = this.pointerMap[event.pointerId];\n // a finger drifted off the screen, ignore it\n if (!pointer) {\n return;\n }\n const outEvent = pointer.out;\n const outTarget = pointer.outTarget;\n this.dispatcher.move(event, browserEvent);\n if (outEvent && outTarget !== event.target) {\n outEvent.relatedTarget = event.target;\n event.relatedTarget = outTarget;\n // recover from retargeting by shadow\n outEvent.target = outTarget;\n if (event.target) {\n this.dispatcher.leaveOut(outEvent, browserEvent);\n this.dispatcher.enterOver(event, browserEvent);\n } else {\n // clean up case when finger leaves the screen\n event.target = outTarget;\n event.relatedTarget = null;\n this.cancelOut_(browserEvent, event);\n }\n }\n pointer.out = event;\n pointer.outTarget = event.target;\n};\n\n\n/**\n * Handler for `touchend`, triggers `pointerup`,\n * `pointerout` and `pointerleave` events.\n *\n * @param {Event} inEvent The event.\n */\nTouchSource.prototype.touchend = function(inEvent) {\n this.dedupSynthMouse_(inEvent);\n this.processTouches_(inEvent, this.upOut_);\n};\n\n\n/**\n * @private\n * @param {Event} browserEvent An event.\n * @param {Object} inPointer The inPointer object.\n */\nTouchSource.prototype.upOut_ = function(browserEvent, inPointer) {\n this.dispatcher.up(inPointer, browserEvent);\n this.dispatcher.out(inPointer, browserEvent);\n this.dispatcher.leave(inPointer, browserEvent);\n this.cleanUpPointer_(inPointer);\n};\n\n\n/**\n * Handler for `touchcancel`, triggers `pointercancel`,\n * `pointerout` and `pointerleave` events.\n *\n * @param {Event} inEvent The in event.\n */\nTouchSource.prototype.touchcancel = function(inEvent) {\n this.processTouches_(inEvent, this.cancelOut_);\n};\n\n\n/**\n * @private\n * @param {Event} browserEvent The event.\n * @param {Object} inPointer The in pointer.\n */\nTouchSource.prototype.cancelOut_ = function(browserEvent, inPointer) {\n this.dispatcher.cancel(inPointer, browserEvent);\n this.dispatcher.out(inPointer, browserEvent);\n this.dispatcher.leave(inPointer, browserEvent);\n this.cleanUpPointer_(inPointer);\n};\n\n\n/**\n * @private\n * @param {Object} inPointer The inPointer object.\n */\nTouchSource.prototype.cleanUpPointer_ = function(inPointer) {\n delete this.pointerMap[inPointer.pointerId];\n this.removePrimaryPointer_(inPointer);\n};\n\n\n/**\n * Prevent synth mouse events from creating pointer events.\n *\n * @private\n * @param {Event} inEvent The in event.\n */\nTouchSource.prototype.dedupSynthMouse_ = function(inEvent) {\n const lts = this.mouseSource.lastTouches;\n const t = inEvent.changedTouches[0];\n // only the primary finger will synth mouse events\n if (this.isPrimaryTouch_(t)) {\n // remember x/y of last touch\n const lt = [t.clientX, t.clientY];\n lts.push(lt);\n\n setTimeout(function() {\n // remove touch after timeout\n remove(lts, lt);\n }, this.dedupTimeout_);\n }\n};\nexport default TouchSource;\n","/**\n * @module ol/pointer/PointerEventHandler\n */\n// Based on https://github.com/Polymer/PointerEvents\n\n// Copyright (c) 2013 The Polymer Authors. All rights reserved.\n//\n// Redistribution and use in source and binary forms, with or without\n// modification, are permitted provided that the following conditions are\n// met:\n//\n// * Redistributions of source code must retain the above copyright\n// notice, this list of conditions and the following disclaimer.\n// * Redistributions in binary form must reproduce the above\n// copyright notice, this list of conditions and the following disclaimer\n// in the documentation and/or other materials provided with the\n// distribution.\n// * Neither the name of Google Inc. nor the names of its\n// contributors may be used to endorse or promote products derived from\n// this software without specific prior written permission.\n//\n// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n// \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\nimport {inherits} from '../util.js';\nimport {listen, unlisten} from '../events.js';\nimport EventTarget from '../events/EventTarget.js';\nimport {POINTER, MSPOINTER, TOUCH} from '../has.js';\nimport PointerEventType from '../pointer/EventType.js';\nimport MouseSource from '../pointer/MouseSource.js';\nimport MsSource from '../pointer/MsSource.js';\nimport NativeSource from '../pointer/NativeSource.js';\nimport PointerEvent from '../pointer/PointerEvent.js';\nimport TouchSource from '../pointer/TouchSource.js';\n\n/**\n * @constructor\n * @extends {module:ol/events/EventTarget}\n * @param {Element|HTMLDocument} element Viewport element.\n */\nconst PointerEventHandler = function(element) {\n EventTarget.call(this);\n\n /**\n * @const\n * @private\n * @type {Element|HTMLDocument}\n */\n this.element_ = element;\n\n /**\n * @const\n * @type {!Object.}\n */\n this.pointerMap = {};\n\n /**\n * @type {Object.}\n * @private\n */\n this.eventMap_ = {};\n\n /**\n * @type {Array.}\n * @private\n */\n this.eventSourceList_ = [];\n\n this.registerSources();\n};\n\ninherits(PointerEventHandler, EventTarget);\n\n/**\n * Properties to copy when cloning an event, with default values.\n * @type {Array.}\n */\nconst CLONE_PROPS = [\n // MouseEvent\n ['bubbles', false],\n ['cancelable', false],\n ['view', null],\n ['detail', null],\n ['screenX', 0],\n ['screenY', 0],\n ['clientX', 0],\n ['clientY', 0],\n ['ctrlKey', false],\n ['altKey', false],\n ['shiftKey', false],\n ['metaKey', false],\n ['button', 0],\n ['relatedTarget', null],\n // DOM Level 3\n ['buttons', 0],\n // PointerEvent\n ['pointerId', 0],\n ['width', 0],\n ['height', 0],\n ['pressure', 0],\n ['tiltX', 0],\n ['tiltY', 0],\n ['pointerType', ''],\n ['hwTimestamp', 0],\n ['isPrimary', false],\n // event instance\n ['type', ''],\n ['target', null],\n ['currentTarget', null],\n ['which', 0]\n];\n\n\n/**\n * Set up the event sources (mouse, touch and native pointers)\n * that generate pointer events.\n */\nPointerEventHandler.prototype.registerSources = function() {\n if (POINTER) {\n this.registerSource('native', new NativeSource(this));\n } else if (MSPOINTER) {\n this.registerSource('ms', new MsSource(this));\n } else {\n const mouseSource = new MouseSource(this);\n this.registerSource('mouse', mouseSource);\n\n if (TOUCH) {\n this.registerSource('touch', new TouchSource(this, mouseSource));\n }\n }\n\n // register events on the viewport element\n this.register_();\n};\n\n\n/**\n * Add a new event source that will generate pointer events.\n *\n * @param {string} name A name for the event source\n * @param {module:ol/pointer/EventSource} source The source event.\n */\nPointerEventHandler.prototype.registerSource = function(name, source) {\n const s = source;\n const newEvents = s.getEvents();\n\n if (newEvents) {\n newEvents.forEach(function(e) {\n const handler = s.getHandlerForEvent(e);\n\n if (handler) {\n this.eventMap_[e] = handler.bind(s);\n }\n }.bind(this));\n this.eventSourceList_.push(s);\n }\n};\n\n\n/**\n * Set up the events for all registered event sources.\n * @private\n */\nPointerEventHandler.prototype.register_ = function() {\n const l = this.eventSourceList_.length;\n for (let i = 0; i < l; i++) {\n const eventSource = this.eventSourceList_[i];\n this.addEvents_(eventSource.getEvents());\n }\n};\n\n\n/**\n * Remove all registered events.\n * @private\n */\nPointerEventHandler.prototype.unregister_ = function() {\n const l = this.eventSourceList_.length;\n for (let i = 0; i < l; i++) {\n const eventSource = this.eventSourceList_[i];\n this.removeEvents_(eventSource.getEvents());\n }\n};\n\n\n/**\n * Calls the right handler for a new event.\n * @private\n * @param {Event} inEvent Browser event.\n */\nPointerEventHandler.prototype.eventHandler_ = function(inEvent) {\n const type = inEvent.type;\n const handler = this.eventMap_[type];\n if (handler) {\n handler(inEvent);\n }\n};\n\n\n/**\n * Setup listeners for the given events.\n * @private\n * @param {Array.} events List of events.\n */\nPointerEventHandler.prototype.addEvents_ = function(events) {\n events.forEach(function(eventName) {\n listen(this.element_, eventName, this.eventHandler_, this);\n }.bind(this));\n};\n\n\n/**\n * Unregister listeners for the given events.\n * @private\n * @param {Array.} events List of events.\n */\nPointerEventHandler.prototype.removeEvents_ = function(events) {\n events.forEach(function(e) {\n unlisten(this.element_, e, this.eventHandler_, this);\n }.bind(this));\n};\n\n\n/**\n * Returns a snapshot of inEvent, with writable properties.\n *\n * @param {Event} event Browser event.\n * @param {Event|Touch} inEvent An event that contains\n * properties to copy.\n * @return {Object} An object containing shallow copies of\n * `inEvent`'s properties.\n */\nPointerEventHandler.prototype.cloneEvent = function(event, inEvent) {\n const eventCopy = {};\n for (let i = 0, ii = CLONE_PROPS.length; i < ii; i++) {\n const p = CLONE_PROPS[i][0];\n eventCopy[p] = event[p] || inEvent[p] || CLONE_PROPS[i][1];\n }\n\n return eventCopy;\n};\n\n\n// EVENTS\n\n\n/**\n * Triggers a 'pointerdown' event.\n * @param {Object} data Pointer event data.\n * @param {Event} event The event.\n */\nPointerEventHandler.prototype.down = function(data, event) {\n this.fireEvent(PointerEventType.POINTERDOWN, data, event);\n};\n\n\n/**\n * Triggers a 'pointermove' event.\n * @param {Object} data Pointer event data.\n * @param {Event} event The event.\n */\nPointerEventHandler.prototype.move = function(data, event) {\n this.fireEvent(PointerEventType.POINTERMOVE, data, event);\n};\n\n\n/**\n * Triggers a 'pointerup' event.\n * @param {Object} data Pointer event data.\n * @param {Event} event The event.\n */\nPointerEventHandler.prototype.up = function(data, event) {\n this.fireEvent(PointerEventType.POINTERUP, data, event);\n};\n\n\n/**\n * Triggers a 'pointerenter' event.\n * @param {Object} data Pointer event data.\n * @param {Event} event The event.\n */\nPointerEventHandler.prototype.enter = function(data, event) {\n data.bubbles = false;\n this.fireEvent(PointerEventType.POINTERENTER, data, event);\n};\n\n\n/**\n * Triggers a 'pointerleave' event.\n * @param {Object} data Pointer event data.\n * @param {Event} event The event.\n */\nPointerEventHandler.prototype.leave = function(data, event) {\n data.bubbles = false;\n this.fireEvent(PointerEventType.POINTERLEAVE, data, event);\n};\n\n\n/**\n * Triggers a 'pointerover' event.\n * @param {Object} data Pointer event data.\n * @param {Event} event The event.\n */\nPointerEventHandler.prototype.over = function(data, event) {\n data.bubbles = true;\n this.fireEvent(PointerEventType.POINTEROVER, data, event);\n};\n\n\n/**\n * Triggers a 'pointerout' event.\n * @param {Object} data Pointer event data.\n * @param {Event} event The event.\n */\nPointerEventHandler.prototype.out = function(data, event) {\n data.bubbles = true;\n this.fireEvent(PointerEventType.POINTEROUT, data, event);\n};\n\n\n/**\n * Triggers a 'pointercancel' event.\n * @param {Object} data Pointer event data.\n * @param {Event} event The event.\n */\nPointerEventHandler.prototype.cancel = function(data, event) {\n this.fireEvent(PointerEventType.POINTERCANCEL, data, event);\n};\n\n\n/**\n * Triggers a combination of 'pointerout' and 'pointerleave' events.\n * @param {Object} data Pointer event data.\n * @param {Event} event The event.\n */\nPointerEventHandler.prototype.leaveOut = function(data, event) {\n this.out(data, event);\n if (!this.contains_(data.target, data.relatedTarget)) {\n this.leave(data, event);\n }\n};\n\n\n/**\n * Triggers a combination of 'pointerover' and 'pointerevents' events.\n * @param {Object} data Pointer event data.\n * @param {Event} event The event.\n */\nPointerEventHandler.prototype.enterOver = function(data, event) {\n this.over(data, event);\n if (!this.contains_(data.target, data.relatedTarget)) {\n this.enter(data, event);\n }\n};\n\n\n/**\n * @private\n * @param {Element} container The container element.\n * @param {Element} contained The contained element.\n * @return {boolean} Returns true if the container element\n * contains the other element.\n */\nPointerEventHandler.prototype.contains_ = function(container, contained) {\n if (!container || !contained) {\n return false;\n }\n return container.contains(contained);\n};\n\n\n// EVENT CREATION AND TRACKING\n/**\n * Creates a new Event of type `inType`, based on the information in\n * `data`.\n *\n * @param {string} inType A string representing the type of event to create.\n * @param {Object} data Pointer event data.\n * @param {Event} event The event.\n * @return {module:ol/pointer/PointerEvent} A PointerEvent of type `inType`.\n */\nPointerEventHandler.prototype.makeEvent = function(inType, data, event) {\n return new PointerEvent(inType, event, data);\n};\n\n\n/**\n * Make and dispatch an event in one call.\n * @param {string} inType A string representing the type of event.\n * @param {Object} data Pointer event data.\n * @param {Event} event The event.\n */\nPointerEventHandler.prototype.fireEvent = function(inType, data, event) {\n const e = this.makeEvent(inType, data, event);\n this.dispatchEvent(e);\n};\n\n\n/**\n * Creates a pointer event from a native pointer event\n * and dispatches this event.\n * @param {Event} event A platform event with a target.\n */\nPointerEventHandler.prototype.fireNativeEvent = function(event) {\n const e = this.makeEvent(event.type, event, event);\n this.dispatchEvent(e);\n};\n\n\n/**\n * Wrap a native mouse event into a pointer event.\n * This proxy method is required for the legacy IE support.\n * @param {string} eventType The pointer event type.\n * @param {Event} event The event.\n * @return {module:ol/pointer/PointerEvent} The wrapped event.\n */\nPointerEventHandler.prototype.wrapMouseEvent = function(eventType, event) {\n const pointerEvent = this.makeEvent(\n eventType, MouseSource.prepareEvent(event, this), event);\n return pointerEvent;\n};\n\n\n/**\n * @inheritDoc\n */\nPointerEventHandler.prototype.disposeInternal = function() {\n this.unregister_();\n EventTarget.prototype.disposeInternal.call(this);\n};\n\n\nexport default PointerEventHandler;\n","/**\n * @module ol/MapBrowserEventHandler\n */\nimport {inherits} from './util.js';\nimport {DEVICE_PIXEL_RATIO} from './has.js';\nimport MapBrowserEventType from './MapBrowserEventType.js';\nimport MapBrowserPointerEvent from './MapBrowserPointerEvent.js';\nimport {listen, unlistenByKey} from './events.js';\nimport EventTarget from './events/EventTarget.js';\nimport PointerEventType from './pointer/EventType.js';\nimport PointerEventHandler from './pointer/PointerEventHandler.js';\n\n/**\n * @param {module:ol/PluggableMap} map The map with the viewport to\n * listen to events on.\n * @param {number=} moveTolerance The minimal distance the pointer must travel\n * to trigger a move.\n * @constructor\n * @extends {module:ol/events/EventTarget}\n */\nconst MapBrowserEventHandler = function(map, moveTolerance) {\n\n EventTarget.call(this);\n\n /**\n * This is the element that we will listen to the real events on.\n * @type {module:ol/PluggableMap}\n * @private\n */\n this.map_ = map;\n\n /**\n * @type {number}\n * @private\n */\n this.clickTimeoutId_ = 0;\n\n /**\n * @type {boolean}\n * @private\n */\n this.dragging_ = false;\n\n /**\n * @type {!Array.}\n * @private\n */\n this.dragListenerKeys_ = [];\n\n /**\n * @type {number}\n * @private\n */\n this.moveTolerance_ = moveTolerance ?\n moveTolerance * DEVICE_PIXEL_RATIO : DEVICE_PIXEL_RATIO;\n\n /**\n * The most recent \"down\" type event (or null if none have occurred).\n * Set on pointerdown.\n * @type {module:ol/pointer/PointerEvent}\n * @private\n */\n this.down_ = null;\n\n const element = this.map_.getViewport();\n\n /**\n * @type {number}\n * @private\n */\n this.activePointers_ = 0;\n\n /**\n * @type {!Object.}\n * @private\n */\n this.trackedTouches_ = {};\n\n /**\n * Event handler which generates pointer events for\n * the viewport element.\n *\n * @type {module:ol/pointer/PointerEventHandler}\n * @private\n */\n this.pointerEventHandler_ = new PointerEventHandler(element);\n\n /**\n * Event handler which generates pointer events for\n * the document (used when dragging).\n *\n * @type {module:ol/pointer/PointerEventHandler}\n * @private\n */\n this.documentPointerEventHandler_ = null;\n\n /**\n * @type {?module:ol/events~EventsKey}\n * @private\n */\n this.pointerdownListenerKey_ = listen(this.pointerEventHandler_,\n PointerEventType.POINTERDOWN,\n this.handlePointerDown_, this);\n\n /**\n * @type {?module:ol/events~EventsKey}\n * @private\n */\n this.relayedListenerKey_ = listen(this.pointerEventHandler_,\n PointerEventType.POINTERMOVE,\n this.relayEvent_, this);\n\n};\n\ninherits(MapBrowserEventHandler, EventTarget);\n\n\n/**\n * @param {module:ol/pointer/PointerEvent} pointerEvent Pointer\n * event.\n * @private\n */\nMapBrowserEventHandler.prototype.emulateClick_ = function(pointerEvent) {\n let newEvent = new MapBrowserPointerEvent(\n MapBrowserEventType.CLICK, this.map_, pointerEvent);\n this.dispatchEvent(newEvent);\n if (this.clickTimeoutId_ !== 0) {\n // double-click\n clearTimeout(this.clickTimeoutId_);\n this.clickTimeoutId_ = 0;\n newEvent = new MapBrowserPointerEvent(\n MapBrowserEventType.DBLCLICK, this.map_, pointerEvent);\n this.dispatchEvent(newEvent);\n } else {\n // click\n this.clickTimeoutId_ = setTimeout(function() {\n this.clickTimeoutId_ = 0;\n const newEvent = new MapBrowserPointerEvent(\n MapBrowserEventType.SINGLECLICK, this.map_, pointerEvent);\n this.dispatchEvent(newEvent);\n }.bind(this), 250);\n }\n};\n\n\n/**\n * Keeps track on how many pointers are currently active.\n *\n * @param {module:ol/pointer/PointerEvent} pointerEvent Pointer\n * event.\n * @private\n */\nMapBrowserEventHandler.prototype.updateActivePointers_ = function(pointerEvent) {\n const event = pointerEvent;\n\n if (event.type == MapBrowserEventType.POINTERUP ||\n event.type == MapBrowserEventType.POINTERCANCEL) {\n delete this.trackedTouches_[event.pointerId];\n } else if (event.type == MapBrowserEventType.POINTERDOWN) {\n this.trackedTouches_[event.pointerId] = true;\n }\n this.activePointers_ = Object.keys(this.trackedTouches_).length;\n};\n\n\n/**\n * @param {module:ol/pointer/PointerEvent} pointerEvent Pointer\n * event.\n * @private\n */\nMapBrowserEventHandler.prototype.handlePointerUp_ = function(pointerEvent) {\n this.updateActivePointers_(pointerEvent);\n const newEvent = new MapBrowserPointerEvent(\n MapBrowserEventType.POINTERUP, this.map_, pointerEvent);\n this.dispatchEvent(newEvent);\n\n // We emulate click events on left mouse button click, touch contact, and pen\n // contact. isMouseActionButton returns true in these cases (evt.button is set\n // to 0).\n // See http://www.w3.org/TR/pointerevents/#button-states\n // We only fire click, singleclick, and doubleclick if nobody has called\n // event.stopPropagation() or event.preventDefault().\n if (!newEvent.propagationStopped && !this.dragging_ && this.isMouseActionButton_(pointerEvent)) {\n this.emulateClick_(this.down_);\n }\n\n if (this.activePointers_ === 0) {\n this.dragListenerKeys_.forEach(unlistenByKey);\n this.dragListenerKeys_.length = 0;\n this.dragging_ = false;\n this.down_ = null;\n this.documentPointerEventHandler_.dispose();\n this.documentPointerEventHandler_ = null;\n }\n};\n\n\n/**\n * @param {module:ol/pointer/PointerEvent} pointerEvent Pointer\n * event.\n * @return {boolean} If the left mouse button was pressed.\n * @private\n */\nMapBrowserEventHandler.prototype.isMouseActionButton_ = function(pointerEvent) {\n return pointerEvent.button === 0;\n};\n\n\n/**\n * @param {module:ol/pointer/PointerEvent} pointerEvent Pointer\n * event.\n * @private\n */\nMapBrowserEventHandler.prototype.handlePointerDown_ = function(pointerEvent) {\n this.updateActivePointers_(pointerEvent);\n const newEvent = new MapBrowserPointerEvent(\n MapBrowserEventType.POINTERDOWN, this.map_, pointerEvent);\n this.dispatchEvent(newEvent);\n\n this.down_ = pointerEvent;\n\n if (this.dragListenerKeys_.length === 0) {\n /* Set up a pointer event handler on the `document`,\n * which is required when the pointer is moved outside\n * the viewport when dragging.\n */\n this.documentPointerEventHandler_ =\n new PointerEventHandler(document);\n\n this.dragListenerKeys_.push(\n listen(this.documentPointerEventHandler_,\n MapBrowserEventType.POINTERMOVE,\n this.handlePointerMove_, this),\n listen(this.documentPointerEventHandler_,\n MapBrowserEventType.POINTERUP,\n this.handlePointerUp_, this),\n /* Note that the listener for `pointercancel is set up on\n * `pointerEventHandler_` and not `documentPointerEventHandler_` like\n * the `pointerup` and `pointermove` listeners.\n *\n * The reason for this is the following: `TouchSource.vacuumTouches_()`\n * issues `pointercancel` events, when there was no `touchend` for a\n * `touchstart`. Now, let's say a first `touchstart` is registered on\n * `pointerEventHandler_`. The `documentPointerEventHandler_` is set up.\n * But `documentPointerEventHandler_` doesn't know about the first\n * `touchstart`. If there is no `touchend` for the `touchstart`, we can\n * only receive a `touchcancel` from `pointerEventHandler_`, because it is\n * only registered there.\n */\n listen(this.pointerEventHandler_,\n MapBrowserEventType.POINTERCANCEL,\n this.handlePointerUp_, this)\n );\n }\n};\n\n\n/**\n * @param {module:ol/pointer/PointerEvent} pointerEvent Pointer\n * event.\n * @private\n */\nMapBrowserEventHandler.prototype.handlePointerMove_ = function(pointerEvent) {\n // Between pointerdown and pointerup, pointermove events are triggered.\n // To avoid a 'false' touchmove event to be dispatched, we test if the pointer\n // moved a significant distance.\n if (this.isMoving_(pointerEvent)) {\n this.dragging_ = true;\n const newEvent = new MapBrowserPointerEvent(\n MapBrowserEventType.POINTERDRAG, this.map_, pointerEvent,\n this.dragging_);\n this.dispatchEvent(newEvent);\n }\n\n // Some native android browser triggers mousemove events during small period\n // of time. See: https://code.google.com/p/android/issues/detail?id=5491 or\n // https://code.google.com/p/android/issues/detail?id=19827\n // ex: Galaxy Tab P3110 + Android 4.1.1\n pointerEvent.preventDefault();\n};\n\n\n/**\n * Wrap and relay a pointer event. Note that this requires that the type\n * string for the MapBrowserPointerEvent matches the PointerEvent type.\n * @param {module:ol/pointer/PointerEvent} pointerEvent Pointer\n * event.\n * @private\n */\nMapBrowserEventHandler.prototype.relayEvent_ = function(pointerEvent) {\n const dragging = !!(this.down_ && this.isMoving_(pointerEvent));\n this.dispatchEvent(new MapBrowserPointerEvent(\n pointerEvent.type, this.map_, pointerEvent, dragging));\n};\n\n\n/**\n * @param {module:ol/pointer/PointerEvent} pointerEvent Pointer\n * event.\n * @return {boolean} Is moving.\n * @private\n */\nMapBrowserEventHandler.prototype.isMoving_ = function(pointerEvent) {\n return this.dragging_ ||\n Math.abs(pointerEvent.clientX - this.down_.clientX) > this.moveTolerance_ ||\n Math.abs(pointerEvent.clientY - this.down_.clientY) > this.moveTolerance_;\n};\n\n\n/**\n * @inheritDoc\n */\nMapBrowserEventHandler.prototype.disposeInternal = function() {\n if (this.relayedListenerKey_) {\n unlistenByKey(this.relayedListenerKey_);\n this.relayedListenerKey_ = null;\n }\n if (this.pointerdownListenerKey_) {\n unlistenByKey(this.pointerdownListenerKey_);\n this.pointerdownListenerKey_ = null;\n }\n\n this.dragListenerKeys_.forEach(unlistenByKey);\n this.dragListenerKeys_.length = 0;\n\n if (this.documentPointerEventHandler_) {\n this.documentPointerEventHandler_.dispose();\n this.documentPointerEventHandler_ = null;\n }\n if (this.pointerEventHandler_) {\n this.pointerEventHandler_.dispose();\n this.pointerEventHandler_ = null;\n }\n EventTarget.prototype.disposeInternal.call(this);\n};\nexport default MapBrowserEventHandler;\n","/**\n * @module ol/MapEventType\n */\n\n/**\n * @enum {string}\n */\nexport default {\n\n /**\n * Triggered after a map frame is rendered.\n * @event module:ol/MapEvent~MapEvent#postrender\n * @api\n */\n POSTRENDER: 'postrender',\n\n /**\n * Triggered when the map starts moving.\n * @event module:ol/MapEvent~MapEvent#movestart\n * @api\n */\n MOVESTART: 'movestart',\n\n /**\n * Triggered after the map is moved.\n * @event module:ol/MapEvent~MapEvent#moveend\n * @api\n */\n MOVEEND: 'moveend'\n\n};\n","/**\n * @module ol/MapProperty\n */\n\n/**\n * @enum {string}\n */\nexport default {\n LAYERGROUP: 'layergroup',\n SIZE: 'size',\n TARGET: 'target',\n VIEW: 'view'\n};\n","/**\n * @module ol/structs/PriorityQueue\n */\nimport {assert} from '../asserts.js';\nimport {clear} from '../obj.js';\n\n/**\n * Priority queue.\n *\n * The implementation is inspired from the Closure Library's Heap class and\n * Python's heapq module.\n *\n * @see http://closure-library.googlecode.com/svn/docs/closure_goog_structs_heap.js.source.html\n * @see http://hg.python.org/cpython/file/2.7/Lib/heapq.py\n *\n * @constructor\n * @param {function(T): number} priorityFunction Priority function.\n * @param {function(T): string} keyFunction Key function.\n * @struct\n * @template T\n */\nconst PriorityQueue = function(priorityFunction, keyFunction) {\n\n /**\n * @type {function(T): number}\n * @private\n */\n this.priorityFunction_ = priorityFunction;\n\n /**\n * @type {function(T): string}\n * @private\n */\n this.keyFunction_ = keyFunction;\n\n /**\n * @type {Array.}\n * @private\n */\n this.elements_ = [];\n\n /**\n * @type {Array.}\n * @private\n */\n this.priorities_ = [];\n\n /**\n * @type {!Object.}\n * @private\n */\n this.queuedElements_ = {};\n\n};\n\n\n/**\n * @type {number}\n */\nexport const DROP = Infinity;\n\n\n/**\n * FIXME empty description for jsdoc\n */\nPriorityQueue.prototype.clear = function() {\n this.elements_.length = 0;\n this.priorities_.length = 0;\n clear(this.queuedElements_);\n};\n\n\n/**\n * Remove and return the highest-priority element. O(log N).\n * @return {T} Element.\n */\nPriorityQueue.prototype.dequeue = function() {\n const elements = this.elements_;\n const priorities = this.priorities_;\n const element = elements[0];\n if (elements.length == 1) {\n elements.length = 0;\n priorities.length = 0;\n } else {\n elements[0] = elements.pop();\n priorities[0] = priorities.pop();\n this.siftUp_(0);\n }\n const elementKey = this.keyFunction_(element);\n delete this.queuedElements_[elementKey];\n return element;\n};\n\n\n/**\n * Enqueue an element. O(log N).\n * @param {T} element Element.\n * @return {boolean} The element was added to the queue.\n */\nPriorityQueue.prototype.enqueue = function(element) {\n assert(!(this.keyFunction_(element) in this.queuedElements_),\n 31); // Tried to enqueue an `element` that was already added to the queue\n const priority = this.priorityFunction_(element);\n if (priority != DROP) {\n this.elements_.push(element);\n this.priorities_.push(priority);\n this.queuedElements_[this.keyFunction_(element)] = true;\n this.siftDown_(0, this.elements_.length - 1);\n return true;\n }\n return false;\n};\n\n\n/**\n * @return {number} Count.\n */\nPriorityQueue.prototype.getCount = function() {\n return this.elements_.length;\n};\n\n\n/**\n * Gets the index of the left child of the node at the given index.\n * @param {number} index The index of the node to get the left child for.\n * @return {number} The index of the left child.\n * @private\n */\nPriorityQueue.prototype.getLeftChildIndex_ = function(index) {\n return index * 2 + 1;\n};\n\n\n/**\n * Gets the index of the right child of the node at the given index.\n * @param {number} index The index of the node to get the right child for.\n * @return {number} The index of the right child.\n * @private\n */\nPriorityQueue.prototype.getRightChildIndex_ = function(index) {\n return index * 2 + 2;\n};\n\n\n/**\n * Gets the index of the parent of the node at the given index.\n * @param {number} index The index of the node to get the parent for.\n * @return {number} The index of the parent.\n * @private\n */\nPriorityQueue.prototype.getParentIndex_ = function(index) {\n return (index - 1) >> 1;\n};\n\n\n/**\n * Make this a heap. O(N).\n * @private\n */\nPriorityQueue.prototype.heapify_ = function() {\n let i;\n for (i = (this.elements_.length >> 1) - 1; i >= 0; i--) {\n this.siftUp_(i);\n }\n};\n\n\n/**\n * @return {boolean} Is empty.\n */\nPriorityQueue.prototype.isEmpty = function() {\n return this.elements_.length === 0;\n};\n\n\n/**\n * @param {string} key Key.\n * @return {boolean} Is key queued.\n */\nPriorityQueue.prototype.isKeyQueued = function(key) {\n return key in this.queuedElements_;\n};\n\n\n/**\n * @param {T} element Element.\n * @return {boolean} Is queued.\n */\nPriorityQueue.prototype.isQueued = function(element) {\n return this.isKeyQueued(this.keyFunction_(element));\n};\n\n\n/**\n * @param {number} index The index of the node to move down.\n * @private\n */\nPriorityQueue.prototype.siftUp_ = function(index) {\n const elements = this.elements_;\n const priorities = this.priorities_;\n const count = elements.length;\n const element = elements[index];\n const priority = priorities[index];\n const startIndex = index;\n\n while (index < (count >> 1)) {\n const lIndex = this.getLeftChildIndex_(index);\n const rIndex = this.getRightChildIndex_(index);\n\n const smallerChildIndex = rIndex < count &&\n priorities[rIndex] < priorities[lIndex] ?\n rIndex : lIndex;\n\n elements[index] = elements[smallerChildIndex];\n priorities[index] = priorities[smallerChildIndex];\n index = smallerChildIndex;\n }\n\n elements[index] = element;\n priorities[index] = priority;\n this.siftDown_(startIndex, index);\n};\n\n\n/**\n * @param {number} startIndex The index of the root.\n * @param {number} index The index of the node to move up.\n * @private\n */\nPriorityQueue.prototype.siftDown_ = function(startIndex, index) {\n const elements = this.elements_;\n const priorities = this.priorities_;\n const element = elements[index];\n const priority = priorities[index];\n\n while (index > startIndex) {\n const parentIndex = this.getParentIndex_(index);\n if (priorities[parentIndex] > priority) {\n elements[index] = elements[parentIndex];\n priorities[index] = priorities[parentIndex];\n index = parentIndex;\n } else {\n break;\n }\n }\n elements[index] = element;\n priorities[index] = priority;\n};\n\n\n/**\n * FIXME empty description for jsdoc\n */\nPriorityQueue.prototype.reprioritize = function() {\n const priorityFunction = this.priorityFunction_;\n const elements = this.elements_;\n const priorities = this.priorities_;\n let index = 0;\n const n = elements.length;\n let element, i, priority;\n for (i = 0; i < n; ++i) {\n element = elements[i];\n priority = priorityFunction(element);\n if (priority == DROP) {\n delete this.queuedElements_[this.keyFunction_(element)];\n } else {\n priorities[index] = priority;\n elements[index++] = element;\n }\n }\n elements.length = index;\n priorities.length = index;\n this.heapify_();\n};\nexport default PriorityQueue;\n","/**\n * @module ol/TileQueue\n */\nimport {inherits} from './util.js';\nimport TileState from './TileState.js';\nimport {listen, unlisten} from './events.js';\nimport EventType from './events/EventType.js';\nimport PriorityQueue from './structs/PriorityQueue.js';\n\n\n/**\n * @typedef {function(module:ol/Tile, string, module:ol/coordinate~Coordinate, number): number} PriorityFunction\n */\n\n\n/**\n * @constructor\n * @extends {module:ol/structs/PriorityQueue.}\n * @param {module:ol/TileQueue~PriorityFunction} tilePriorityFunction\n * Tile priority function.\n * @param {function(): ?} tileChangeCallback\n * Function called on each tile change event.\n * @struct\n */\nconst TileQueue = function(tilePriorityFunction, tileChangeCallback) {\n\n PriorityQueue.call(\n this,\n /**\n * @param {Array} element Element.\n * @return {number} Priority.\n */\n function(element) {\n return tilePriorityFunction.apply(null, element);\n },\n /**\n * @param {Array} element Element.\n * @return {string} Key.\n */\n function(element) {\n return (/** @type {module:ol/Tile} */ (element[0]).getKey());\n });\n\n /**\n * @private\n * @type {function(): ?}\n */\n this.tileChangeCallback_ = tileChangeCallback;\n\n /**\n * @private\n * @type {number}\n */\n this.tilesLoading_ = 0;\n\n /**\n * @private\n * @type {!Object.}\n */\n this.tilesLoadingKeys_ = {};\n\n};\n\ninherits(TileQueue, PriorityQueue);\n\n\n/**\n * @inheritDoc\n */\nTileQueue.prototype.enqueue = function(element) {\n const added = PriorityQueue.prototype.enqueue.call(this, element);\n if (added) {\n const tile = element[0];\n listen(tile, EventType.CHANGE, this.handleTileChange, this);\n }\n return added;\n};\n\n\n/**\n * @return {number} Number of tiles loading.\n */\nTileQueue.prototype.getTilesLoading = function() {\n return this.tilesLoading_;\n};\n\n\n/**\n * @param {module:ol/events/Event} event Event.\n * @protected\n */\nTileQueue.prototype.handleTileChange = function(event) {\n const tile = /** @type {module:ol/Tile} */ (event.target);\n const state = tile.getState();\n if (state === TileState.LOADED || state === TileState.ERROR ||\n state === TileState.EMPTY || state === TileState.ABORT) {\n unlisten(tile, EventType.CHANGE, this.handleTileChange, this);\n const tileKey = tile.getKey();\n if (tileKey in this.tilesLoadingKeys_) {\n delete this.tilesLoadingKeys_[tileKey];\n --this.tilesLoading_;\n }\n this.tileChangeCallback_();\n }\n};\n\n\n/**\n * @param {number} maxTotalLoading Maximum number tiles to load simultaneously.\n * @param {number} maxNewLoads Maximum number of new tiles to load.\n */\nTileQueue.prototype.loadMoreTiles = function(maxTotalLoading, maxNewLoads) {\n let newLoads = 0;\n let abortedTiles = false;\n let state, tile, tileKey;\n while (this.tilesLoading_ < maxTotalLoading && newLoads < maxNewLoads &&\n this.getCount() > 0) {\n tile = /** @type {module:ol/Tile} */ (this.dequeue()[0]);\n tileKey = tile.getKey();\n state = tile.getState();\n if (state === TileState.ABORT) {\n abortedTiles = true;\n } else if (state === TileState.IDLE && !(tileKey in this.tilesLoadingKeys_)) {\n this.tilesLoadingKeys_[tileKey] = true;\n ++this.tilesLoading_;\n ++newLoads;\n tile.load();\n }\n }\n if (newLoads === 0 && abortedTiles) {\n // Do not stop the render loop when all wanted tiles were aborted due to\n // a small, saturated tile cache.\n this.tileChangeCallback_();\n }\n};\nexport default TileQueue;\n","/**\n * @module ol/tilegrid/common\n */\n\n/**\n * Default maximum zoom for default tile grids.\n * @type {number}\n */\nexport const DEFAULT_MAX_ZOOM = 42;\n\n/**\n * Default tile size.\n * @type {number}\n */\nexport const DEFAULT_TILE_SIZE = 256;\n","/**\n * @module ol/centerconstraint\n */\nimport {clamp} from './math.js';\n\n\n/**\n * @typedef {function((module:ol/coordinate~Coordinate|undefined)): (module:ol/coordinate~Coordinate|undefined)} Type\n */\n\n\n/**\n * @param {module:ol/extent~Extent} extent Extent.\n * @return {module:ol/centerconstraint~Type} The constraint.\n */\nexport function createExtent(extent) {\n return (\n /**\n * @param {module:ol/coordinate~Coordinate=} center Center.\n * @return {module:ol/coordinate~Coordinate|undefined} Center.\n */\n function(center) {\n if (center) {\n return [\n clamp(center[0], extent[0], extent[2]),\n clamp(center[1], extent[1], extent[3])\n ];\n } else {\n return undefined;\n }\n }\n );\n}\n\n\n/**\n * @param {module:ol/coordinate~Coordinate=} center Center.\n * @return {module:ol/coordinate~Coordinate|undefined} Center.\n */\nexport function none(center) {\n return center;\n}\n","/**\n * @module ol/rotationconstraint\n */\nimport {toRadians} from './math.js';\n\n\n/**\n * @typedef {function((number|undefined), number): (number|undefined)} Type\n */\n\n\n/**\n * @param {number|undefined} rotation Rotation.\n * @param {number} delta Delta.\n * @return {number|undefined} Rotation.\n */\nexport function disable(rotation, delta) {\n if (rotation !== undefined) {\n return 0;\n } else {\n return undefined;\n }\n}\n\n\n/**\n * @param {number|undefined} rotation Rotation.\n * @param {number} delta Delta.\n * @return {number|undefined} Rotation.\n */\nexport function none(rotation, delta) {\n if (rotation !== undefined) {\n return rotation + delta;\n } else {\n return undefined;\n }\n}\n\n\n/**\n * @param {number} n N.\n * @return {module:ol/rotationconstraint~Type} Rotation constraint.\n */\nexport function createSnapToN(n) {\n const theta = 2 * Math.PI / n;\n return (\n /**\n * @param {number|undefined} rotation Rotation.\n * @param {number} delta Delta.\n * @return {number|undefined} Rotation.\n */\n function(rotation, delta) {\n if (rotation !== undefined) {\n rotation = Math.floor((rotation + delta) / theta + 0.5) * theta;\n return rotation;\n } else {\n return undefined;\n }\n });\n}\n\n\n/**\n * @param {number=} opt_tolerance Tolerance.\n * @return {module:ol/rotationconstraint~Type} Rotation constraint.\n */\nexport function createSnapToZero(opt_tolerance) {\n const tolerance = opt_tolerance || toRadians(5);\n return (\n /**\n * @param {number|undefined} rotation Rotation.\n * @param {number} delta Delta.\n * @return {number|undefined} Rotation.\n */\n function(rotation, delta) {\n if (rotation !== undefined) {\n if (Math.abs(rotation + delta) <= tolerance) {\n return 0;\n } else {\n return rotation + delta;\n }\n } else {\n return undefined;\n }\n });\n}\n","/**\n * @module ol/ViewHint\n */\n\n/**\n * @enum {number}\n */\nexport default {\n ANIMATING: 0,\n INTERACTING: 1\n};\n","/**\n * @module ol/ViewProperty\n */\n\n/**\n * @enum {string}\n */\nexport default {\n CENTER: 'center',\n RESOLUTION: 'resolution',\n ROTATION: 'rotation'\n};\n","/**\n * @module ol/View\n */\nimport {DEFAULT_TILE_SIZE} from './tilegrid/common.js';\nimport {getUid, inherits} from './util.js';\nimport {UNDEFINED} from './functions.js';\nimport {createExtent, none as centerNone} from './centerconstraint.js';\nimport BaseObject from './Object.js';\nimport {createSnapToResolutions, createSnapToPower} from './resolutionconstraint.js';\nimport {createSnapToZero, createSnapToN, none as rotationNone, disable} from './rotationconstraint.js';\nimport ViewHint from './ViewHint.js';\nimport ViewProperty from './ViewProperty.js';\nimport {linearFindNearest} from './array.js';\nimport {assert} from './asserts.js';\nimport {add as addCoordinate, rotate as rotateCoordinate, equals as coordinatesEqual} from './coordinate.js';\nimport {inAndOut} from './easing.js';\nimport {getForViewAndSize, getCenter, getHeight, getWidth, isEmpty} from './extent.js';\nimport GeometryType from './geom/GeometryType.js';\nimport {fromExtent as polygonFromExtent} from './geom/Polygon.js';\nimport SimpleGeometry from './geom/SimpleGeometry.js';\nimport {clamp, modulo} from './math.js';\nimport {assign} from './obj.js';\nimport {createProjection, METERS_PER_UNIT} from './proj.js';\nimport Units from './proj/Units.js';\n\n\n/**\n * An animation configuration\n *\n * @typedef {Object} Animation\n * @property {module:ol/coordinate~Coordinate} [sourceCenter]\n * @property {module:ol/coordinate~Coordinate} [targetCenter]\n * @property {number} [sourceResolution]\n * @property {number} [targetResolution]\n * @property {number} [sourceRotation]\n * @property {number} [sourceRotation]\n * @property {module:ol/coordinate~Coordinate} [anchor]\n * @property {number} start\n * @property {number} duration\n * @property {boolean} complete\n * @property {function(number):number} easing\n * @property {function(boolean)} callback\n */\n\n\n/**\n * @typedef {Object} Constraints\n * @property {module:ol/centerconstraint~Type} center\n * @property {module:ol/resolutionconstraint~Type} resolution\n * @property {module:ol/rotationconstraint~Type} rotation\n */\n\n\n/**\n * @typedef {Object} FitOptions\n * @property {module:ol/size~Size} [size] The size in pixels of the box to fit\n * the extent into. Default is the current size of the first map in the DOM that\n * uses this view, or `[100, 100]` if no such map is found.\n * @property {!Array.} [padding=[0, 0, 0, 0]] Padding (in pixels) to be\n * cleared inside the view. Values in the array are top, right, bottom and left\n * padding.\n * @property {boolean} [constrainResolution=true] Constrain the resolution.\n * @property {boolean} [nearest=false] If `constrainResolution` is `true`, get\n * the nearest extent instead of the closest that actually fits the view.\n * @property {number} [minResolution=0] Minimum resolution that we zoom to.\n * @property {number} [maxZoom] Maximum zoom level that we zoom to. If\n * `minResolution` is given, this property is ignored.\n * @property {number} [duration] The duration of the animation in milliseconds.\n * By default, there is no animation to the target extent.\n * @property {function(number):number} [easing] The easing function used during\n * the animation (defaults to {@link module:ol/easing~inAndOut}).\n * The function will be called for each frame with a number representing a\n * fraction of the animation's duration. The function should return a number\n * between 0 and 1 representing the progress toward the destination state.\n * @property {function(boolean)} [callback] Function called when the view is in\n * its final position. The callback will be called with `true` if the animation\n * series completed on its own or `false` if it was cancelled.\n */\n\n\n/**\n * @typedef {Object} ViewOptions\n * @property {module:ol/coordinate~Coordinate} [center] The initial center for\n * the view. The coordinate system for the center is specified with the\n * `projection` option. Layer sources will not be fetched if this is not set,\n * but the center can be set later with {@link #setCenter}.\n * @property {boolean|number} [constrainRotation=true] Rotation constraint.\n * `false` means no constraint. `true` means no constraint, but snap to zero\n * near zero. A number constrains the rotation to that number of values. For\n * example, `4` will constrain the rotation to 0, 90, 180, and 270 degrees.\n * @property {boolean} [enableRotation=true] Enable rotation.\n * If `false`, a rotation constraint that always sets the rotation to zero is\n * used. The `constrainRotation` option has no effect if `enableRotation` is\n * `false`.\n * @property {module:ol/extent~Extent} [extent] The extent that constrains the\n * center, in other words, center cannot be set outside this extent.\n * @property {number} [maxResolution] The maximum resolution used to determine\n * the resolution constraint. It is used together with `minResolution` (or\n * `maxZoom`) and `zoomFactor`. If unspecified it is calculated in such a way\n * that the projection's validity extent fits in a 256x256 px tile. If the\n * projection is Spherical Mercator (the default) then `maxResolution` defaults\n * to `40075016.68557849 / 256 = 156543.03392804097`.\n * @property {number} [minResolution] The minimum resolution used to determine\n * the resolution constraint. It is used together with `maxResolution` (or\n * `minZoom`) and `zoomFactor`. If unspecified it is calculated assuming 29\n * zoom levels (with a factor of 2). If the projection is Spherical Mercator\n * (the default) then `minResolution` defaults to\n * `40075016.68557849 / 256 / Math.pow(2, 28) = 0.0005831682455839253`.\n * @property {number} [maxZoom=28] The maximum zoom level used to determine the\n * resolution constraint. It is used together with `minZoom` (or\n * `maxResolution`) and `zoomFactor`. Note that if `minResolution` is also\n * provided, it is given precedence over `maxZoom`.\n * @property {number} [minZoom=0] The minimum zoom level used to determine the\n * resolution constraint. It is used together with `maxZoom` (or\n * `minResolution`) and `zoomFactor`. Note that if `maxResolution` is also\n * provided, it is given precedence over `minZoom`.\n * @property {module:ol/proj~ProjectionLike} [projection='EPSG:3857'] The\n * projection. The default is Spherical Mercator.\n * @property {number} [resolution] The initial resolution for the view. The\n * units are `projection` units per pixel (e.g. meters per pixel). An\n * alternative to setting this is to set `zoom`. Layer sources will not be\n * fetched if neither this nor `zoom` are defined, but they can be set later\n * with {@link #setZoom} or {@link #setResolution}.\n * @property {Array.} [resolutions] Resolutions to determine the\n * resolution constraint. If set the `maxResolution`, `minResolution`,\n * `minZoom`, `maxZoom`, and `zoomFactor` options are ignored.\n * @property {number} [rotation=0] The initial rotation for the view in radians\n * (positive rotation clockwise, 0 means North).\n * @property {number} [zoom] Only used if `resolution` is not defined. Zoom\n * level used to calculate the initial resolution for the view. The initial\n * resolution is determined using the {@link #constrainResolution} method.\n * @property {number} [zoomFactor=2] The zoom factor used to determine the\n * resolution constraint.\n */\n\n\n/**\n * @typedef {Object} AnimationOptions\n * @property {module:ol/coordinate~Coordinate|undefined} center The center of the view at the end of\n * the animation.\n * @property {number|undefined} zoom The zoom level of the view at the end of the\n * animation. This takes precedence over `resolution`.\n * @property {number|undefined} resolution The resolution of the view at the end\n * of the animation. If `zoom` is also provided, this option will be ignored.\n * @property {number|undefined} rotation The rotation of the view at the end of\n * the animation.\n * @property {module:ol/coordinate~Coordinate|undefined} anchor Optional anchor to remained fixed\n * during a rotation or resolution animation.\n * @property {number} [duration=1000] The duration of the animation in milliseconds.\n * @property {function(number):number} [easing] The easing function used\n * during the animation (defaults to {@link module:ol/easing~inAndOut}).\n * The function will be called for each frame with a number representing a\n * fraction of the animation's duration. The function should return a number\n * between 0 and 1 representing the progress toward the destination state.\n */\n\n\n/**\n * @typedef {Object} State\n * @property {module:ol/coordinate~Coordinate} center\n * @property {module:ol/proj/Projection} projection\n * @property {number} resolution\n * @property {number} rotation\n * @property {number} zoom\n */\n\n\n/**\n * Default min zoom level for the map view.\n * @type {number}\n */\nconst DEFAULT_MIN_ZOOM = 0;\n\n\n/**\n * @classdesc\n * A View object represents a simple 2D view of the map.\n *\n * This is the object to act upon to change the center, resolution,\n * and rotation of the map.\n *\n * ### The view states\n *\n * An View is determined by three states: `center`, `resolution`,\n * and `rotation`. Each state has a corresponding getter and setter, e.g.\n * `getCenter` and `setCenter` for the `center` state.\n *\n * An View has a `projection`. The projection determines the\n * coordinate system of the center, and its units determine the units of the\n * resolution (projection units per pixel). The default projection is\n * Spherical Mercator (EPSG:3857).\n *\n * ### The constraints\n *\n * `setCenter`, `setResolution` and `setRotation` can be used to change the\n * states of the view. Any value can be passed to the setters. And the value\n * that is passed to a setter will effectively be the value set in the view,\n * and returned by the corresponding getter.\n *\n * But a View object also has a *resolution constraint*, a\n * *rotation constraint* and a *center constraint*.\n *\n * As said above, no constraints are applied when the setters are used to set\n * new states for the view. Applying constraints is done explicitly through\n * the use of the `constrain*` functions (`constrainResolution` and\n * `constrainRotation` and `constrainCenter`).\n *\n * The main users of the constraints are the interactions and the\n * controls. For example, double-clicking on the map changes the view to\n * the \"next\" resolution. And releasing the fingers after pinch-zooming\n * snaps to the closest resolution (with an animation).\n *\n * The *resolution constraint* snaps to specific resolutions. It is\n * determined by the following options: `resolutions`, `maxResolution`,\n * `maxZoom`, and `zoomFactor`. If `resolutions` is set, the other three\n * options are ignored. See documentation for each option for more\n * information.\n *\n * The *rotation constraint* snaps to specific angles. It is determined\n * by the following options: `enableRotation` and `constrainRotation`.\n * By default the rotation value is snapped to zero when approaching the\n * horizontal.\n *\n * The *center constraint* is determined by the `extent` option. By\n * default the center is not constrained at all.\n *\n * @constructor\n * @extends {module:ol/Object}\n * @param {module:ol/View~ViewOptions=} opt_options View options.\n * @api\n */\nconst View = function(opt_options) {\n BaseObject.call(this);\n\n const options = assign({}, opt_options);\n\n /**\n * @private\n * @type {Array.}\n */\n this.hints_ = [0, 0];\n\n /**\n * @private\n * @type {Array.>}\n */\n this.animations_ = [];\n\n /**\n * @private\n * @type {number|undefined}\n */\n this.updateAnimationKey_;\n\n this.updateAnimations_ = this.updateAnimations_.bind(this);\n\n /**\n * @private\n * @const\n * @type {module:ol/proj/Projection}\n */\n this.projection_ = createProjection(options.projection, 'EPSG:3857');\n\n this.applyOptions_(options);\n};\n\ninherits(View, BaseObject);\n\n\n/**\n * Set up the view with the given options.\n * @param {module:ol/View~ViewOptions} options View options.\n */\nView.prototype.applyOptions_ = function(options) {\n\n /**\n * @type {Object.}\n */\n const properties = {};\n properties[ViewProperty.CENTER] = options.center !== undefined ?\n options.center : null;\n\n const resolutionConstraintInfo = createResolutionConstraint(options);\n\n /**\n * @private\n * @type {number}\n */\n this.maxResolution_ = resolutionConstraintInfo.maxResolution;\n\n /**\n * @private\n * @type {number}\n */\n this.minResolution_ = resolutionConstraintInfo.minResolution;\n\n /**\n * @private\n * @type {number}\n */\n this.zoomFactor_ = resolutionConstraintInfo.zoomFactor;\n\n /**\n * @private\n * @type {Array.|undefined}\n */\n this.resolutions_ = options.resolutions;\n\n /**\n * @private\n * @type {number}\n */\n this.minZoom_ = resolutionConstraintInfo.minZoom;\n\n const centerConstraint = createCenterConstraint(options);\n const resolutionConstraint = resolutionConstraintInfo.constraint;\n const rotationConstraint = createRotationConstraint(options);\n\n /**\n * @private\n * @type {module:ol/View~Constraints}\n */\n this.constraints_ = {\n center: centerConstraint,\n resolution: resolutionConstraint,\n rotation: rotationConstraint\n };\n\n if (options.resolution !== undefined) {\n properties[ViewProperty.RESOLUTION] = options.resolution;\n } else if (options.zoom !== undefined) {\n properties[ViewProperty.RESOLUTION] = this.constrainResolution(\n this.maxResolution_, options.zoom - this.minZoom_);\n\n if (this.resolutions_) { // in case map zoom is out of min/max zoom range\n properties[ViewProperty.RESOLUTION] = clamp(\n Number(this.getResolution() || properties[ViewProperty.RESOLUTION]),\n this.minResolution_, this.maxResolution_);\n }\n }\n properties[ViewProperty.ROTATION] = options.rotation !== undefined ? options.rotation : 0;\n this.setProperties(properties);\n\n /**\n * @private\n * @type {module:ol/View~ViewOptions}\n */\n this.options_ = options;\n\n};\n\n/**\n * Get an updated version of the view options used to construct the view. The\n * current resolution (or zoom), center, and rotation are applied to any stored\n * options. The provided options can be used to apply new min/max zoom or\n * resolution limits.\n * @param {module:ol/View~ViewOptions} newOptions New options to be applied.\n * @return {module:ol/View~ViewOptions} New options updated with the current view state.\n */\nView.prototype.getUpdatedOptions_ = function(newOptions) {\n const options = assign({}, this.options_);\n\n // preserve resolution (or zoom)\n if (options.resolution !== undefined) {\n options.resolution = this.getResolution();\n } else {\n options.zoom = this.getZoom();\n }\n\n // preserve center\n options.center = this.getCenter();\n\n // preserve rotation\n options.rotation = this.getRotation();\n\n return assign({}, options, newOptions);\n};\n\n\n/**\n * Animate the view. The view's center, zoom (or resolution), and rotation\n * can be animated for smooth transitions between view states. For example,\n * to animate the view to a new zoom level:\n *\n * view.animate({zoom: view.getZoom() + 1});\n *\n * By default, the animation lasts one second and uses in-and-out easing. You\n * can customize this behavior by including `duration` (in milliseconds) and\n * `easing` options (see {@link module:ol/easing}).\n *\n * To chain together multiple animations, call the method with multiple\n * animation objects. For example, to first zoom and then pan:\n *\n * view.animate({zoom: 10}, {center: [0, 0]});\n *\n * If you provide a function as the last argument to the animate method, it\n * will get called at the end of an animation series. The callback will be\n * called with `true` if the animation series completed on its own or `false`\n * if it was cancelled.\n *\n * Animations are cancelled by user interactions (e.g. dragging the map) or by\n * calling `view.setCenter()`, `view.setResolution()`, or `view.setRotation()`\n * (or another method that calls one of these).\n *\n * @param {...(module:ol/View~AnimationOptions|function(boolean))} var_args Animation\n * options. Multiple animations can be run in series by passing multiple\n * options objects. To run multiple animations in parallel, call the method\n * multiple times. An optional callback can be provided as a final\n * argument. The callback will be called with a boolean indicating whether\n * the animation completed without being cancelled.\n * @api\n */\nView.prototype.animate = function(var_args) {\n let animationCount = arguments.length;\n let callback;\n if (animationCount > 1 && typeof arguments[animationCount - 1] === 'function') {\n callback = arguments[animationCount - 1];\n --animationCount;\n }\n if (!this.isDef()) {\n // if view properties are not yet set, shortcut to the final state\n const state = arguments[animationCount - 1];\n if (state.center) {\n this.setCenter(state.center);\n }\n if (state.zoom !== undefined) {\n this.setZoom(state.zoom);\n }\n if (state.rotation !== undefined) {\n this.setRotation(state.rotation);\n }\n if (callback) {\n setTimeout(function() {\n callback(true);\n }, 0);\n }\n return;\n }\n let start = Date.now();\n let center = this.getCenter().slice();\n let resolution = this.getResolution();\n let rotation = this.getRotation();\n const series = [];\n for (let i = 0; i < animationCount; ++i) {\n const options = /** @type {module:ol/View~AnimationOptions} */ (arguments[i]);\n\n const animation = /** @type {module:ol/View~Animation} */ ({\n start: start,\n complete: false,\n anchor: options.anchor,\n duration: options.duration !== undefined ? options.duration : 1000,\n easing: options.easing || inAndOut\n });\n\n if (options.center) {\n animation.sourceCenter = center;\n animation.targetCenter = options.center;\n center = animation.targetCenter;\n }\n\n if (options.zoom !== undefined) {\n animation.sourceResolution = resolution;\n animation.targetResolution = this.constrainResolution(\n this.maxResolution_, options.zoom - this.minZoom_, 0);\n resolution = animation.targetResolution;\n } else if (options.resolution) {\n animation.sourceResolution = resolution;\n animation.targetResolution = options.resolution;\n resolution = animation.targetResolution;\n }\n\n if (options.rotation !== undefined) {\n animation.sourceRotation = rotation;\n const delta = modulo(options.rotation - rotation + Math.PI, 2 * Math.PI) - Math.PI;\n animation.targetRotation = rotation + delta;\n rotation = animation.targetRotation;\n }\n\n animation.callback = callback;\n\n // check if animation is a no-op\n if (isNoopAnimation(animation)) {\n animation.complete = true;\n // we still push it onto the series for callback handling\n } else {\n start += animation.duration;\n }\n series.push(animation);\n }\n this.animations_.push(series);\n this.setHint(ViewHint.ANIMATING, 1);\n this.updateAnimations_();\n};\n\n\n/**\n * Determine if the view is being animated.\n * @return {boolean} The view is being animated.\n * @api\n */\nView.prototype.getAnimating = function() {\n return this.hints_[ViewHint.ANIMATING] > 0;\n};\n\n\n/**\n * Determine if the user is interacting with the view, such as panning or zooming.\n * @return {boolean} The view is being interacted with.\n * @api\n */\nView.prototype.getInteracting = function() {\n return this.hints_[ViewHint.INTERACTING] > 0;\n};\n\n\n/**\n * Cancel any ongoing animations.\n * @api\n */\nView.prototype.cancelAnimations = function() {\n this.setHint(ViewHint.ANIMATING, -this.hints_[ViewHint.ANIMATING]);\n for (let i = 0, ii = this.animations_.length; i < ii; ++i) {\n const series = this.animations_[i];\n if (series[0].callback) {\n series[0].callback(false);\n }\n }\n this.animations_.length = 0;\n};\n\n/**\n * Update all animations.\n */\nView.prototype.updateAnimations_ = function() {\n if (this.updateAnimationKey_ !== undefined) {\n cancelAnimationFrame(this.updateAnimationKey_);\n this.updateAnimationKey_ = undefined;\n }\n if (!this.getAnimating()) {\n return;\n }\n const now = Date.now();\n let more = false;\n for (let i = this.animations_.length - 1; i >= 0; --i) {\n const series = this.animations_[i];\n let seriesComplete = true;\n for (let j = 0, jj = series.length; j < jj; ++j) {\n const animation = series[j];\n if (animation.complete) {\n continue;\n }\n const elapsed = now - animation.start;\n let fraction = animation.duration > 0 ? elapsed / animation.duration : 1;\n if (fraction >= 1) {\n animation.complete = true;\n fraction = 1;\n } else {\n seriesComplete = false;\n }\n const progress = animation.easing(fraction);\n if (animation.sourceCenter) {\n const x0 = animation.sourceCenter[0];\n const y0 = animation.sourceCenter[1];\n const x1 = animation.targetCenter[0];\n const y1 = animation.targetCenter[1];\n const x = x0 + progress * (x1 - x0);\n const y = y0 + progress * (y1 - y0);\n this.set(ViewProperty.CENTER, [x, y]);\n }\n if (animation.sourceResolution && animation.targetResolution) {\n const resolution = progress === 1 ?\n animation.targetResolution :\n animation.sourceResolution + progress * (animation.targetResolution - animation.sourceResolution);\n if (animation.anchor) {\n this.set(ViewProperty.CENTER,\n this.calculateCenterZoom(resolution, animation.anchor));\n }\n this.set(ViewProperty.RESOLUTION, resolution);\n }\n if (animation.sourceRotation !== undefined && animation.targetRotation !== undefined) {\n const rotation = progress === 1 ?\n modulo(animation.targetRotation + Math.PI, 2 * Math.PI) - Math.PI :\n animation.sourceRotation + progress * (animation.targetRotation - animation.sourceRotation);\n if (animation.anchor) {\n this.set(ViewProperty.CENTER,\n this.calculateCenterRotate(rotation, animation.anchor));\n }\n this.set(ViewProperty.ROTATION, rotation);\n }\n more = true;\n if (!animation.complete) {\n break;\n }\n }\n if (seriesComplete) {\n this.animations_[i] = null;\n this.setHint(ViewHint.ANIMATING, -1);\n const callback = series[0].callback;\n if (callback) {\n setTimeout(function() {\n callback(true);\n }, 0);\n }\n }\n }\n // prune completed series\n this.animations_ = this.animations_.filter(Boolean);\n if (more && this.updateAnimationKey_ === undefined) {\n this.updateAnimationKey_ = requestAnimationFrame(this.updateAnimations_);\n }\n};\n\n/**\n * @param {number} rotation Target rotation.\n * @param {module:ol/coordinate~Coordinate} anchor Rotation anchor.\n * @return {module:ol/coordinate~Coordinate|undefined} Center for rotation and anchor.\n */\nView.prototype.calculateCenterRotate = function(rotation, anchor) {\n let center;\n const currentCenter = this.getCenter();\n if (currentCenter !== undefined) {\n center = [currentCenter[0] - anchor[0], currentCenter[1] - anchor[1]];\n rotateCoordinate(center, rotation - this.getRotation());\n addCoordinate(center, anchor);\n }\n return center;\n};\n\n\n/**\n * @param {number} resolution Target resolution.\n * @param {module:ol/coordinate~Coordinate} anchor Zoom anchor.\n * @return {module:ol/coordinate~Coordinate|undefined} Center for resolution and anchor.\n */\nView.prototype.calculateCenterZoom = function(resolution, anchor) {\n let center;\n const currentCenter = this.getCenter();\n const currentResolution = this.getResolution();\n if (currentCenter !== undefined && currentResolution !== undefined) {\n const x = anchor[0] - resolution * (anchor[0] - currentCenter[0]) / currentResolution;\n const y = anchor[1] - resolution * (anchor[1] - currentCenter[1]) / currentResolution;\n center = [x, y];\n }\n return center;\n};\n\n\n/**\n * @private\n * @return {module:ol/size~Size} Viewport size or `[100, 100]` when no viewport is found.\n */\nView.prototype.getSizeFromViewport_ = function() {\n const size = [100, 100];\n const selector = '.ol-viewport[data-view=\"' + getUid(this) + '\"]';\n const element = document.querySelector(selector);\n if (element) {\n const metrics = getComputedStyle(element);\n size[0] = parseInt(metrics.width, 10);\n size[1] = parseInt(metrics.height, 10);\n }\n return size;\n};\n\n\n/**\n * Get the constrained center of this view.\n * @param {module:ol/coordinate~Coordinate|undefined} center Center.\n * @return {module:ol/coordinate~Coordinate|undefined} Constrained center.\n * @api\n */\nView.prototype.constrainCenter = function(center) {\n return this.constraints_.center(center);\n};\n\n\n/**\n * Get the constrained resolution of this view.\n * @param {number|undefined} resolution Resolution.\n * @param {number=} opt_delta Delta. Default is `0`.\n * @param {number=} opt_direction Direction. Default is `0`.\n * @return {number|undefined} Constrained resolution.\n * @api\n */\nView.prototype.constrainResolution = function(resolution, opt_delta, opt_direction) {\n const delta = opt_delta || 0;\n const direction = opt_direction || 0;\n return this.constraints_.resolution(resolution, delta, direction);\n};\n\n\n/**\n * Get the constrained rotation of this view.\n * @param {number|undefined} rotation Rotation.\n * @param {number=} opt_delta Delta. Default is `0`.\n * @return {number|undefined} Constrained rotation.\n * @api\n */\nView.prototype.constrainRotation = function(rotation, opt_delta) {\n const delta = opt_delta || 0;\n return this.constraints_.rotation(rotation, delta);\n};\n\n\n/**\n * Get the view center.\n * @return {module:ol/coordinate~Coordinate|undefined} The center of the view.\n * @observable\n * @api\n */\nView.prototype.getCenter = function() {\n return (\n /** @type {module:ol/coordinate~Coordinate|undefined} */ (this.get(ViewProperty.CENTER))\n );\n};\n\n\n/**\n * @return {module:ol/View~Constraints} Constraints.\n */\nView.prototype.getConstraints = function() {\n return this.constraints_;\n};\n\n\n/**\n * @param {Array.=} opt_hints Destination array.\n * @return {Array.} Hint.\n */\nView.prototype.getHints = function(opt_hints) {\n if (opt_hints !== undefined) {\n opt_hints[0] = this.hints_[0];\n opt_hints[1] = this.hints_[1];\n return opt_hints;\n } else {\n return this.hints_.slice();\n }\n};\n\n\n/**\n * Calculate the extent for the current view state and the passed size.\n * The size is the pixel dimensions of the box into which the calculated extent\n * should fit. In most cases you want to get the extent of the entire map,\n * that is `map.getSize()`.\n * @param {module:ol/size~Size=} opt_size Box pixel size. If not provided, the size of the\n * first map that uses this view will be used.\n * @return {module:ol/extent~Extent} Extent.\n * @api\n */\nView.prototype.calculateExtent = function(opt_size) {\n const size = opt_size || this.getSizeFromViewport_();\n const center = /** @type {!module:ol/coordinate~Coordinate} */ (this.getCenter());\n assert(center, 1); // The view center is not defined\n const resolution = /** @type {!number} */ (this.getResolution());\n assert(resolution !== undefined, 2); // The view resolution is not defined\n const rotation = /** @type {!number} */ (this.getRotation());\n assert(rotation !== undefined, 3); // The view rotation is not defined\n\n return getForViewAndSize(center, resolution, rotation, size);\n};\n\n\n/**\n * Get the maximum resolution of the view.\n * @return {number} The maximum resolution of the view.\n * @api\n */\nView.prototype.getMaxResolution = function() {\n return this.maxResolution_;\n};\n\n\n/**\n * Get the minimum resolution of the view.\n * @return {number} The minimum resolution of the view.\n * @api\n */\nView.prototype.getMinResolution = function() {\n return this.minResolution_;\n};\n\n\n/**\n * Get the maximum zoom level for the view.\n * @return {number} The maximum zoom level.\n * @api\n */\nView.prototype.getMaxZoom = function() {\n return /** @type {number} */ (this.getZoomForResolution(this.minResolution_));\n};\n\n\n/**\n * Set a new maximum zoom level for the view.\n * @param {number} zoom The maximum zoom level.\n * @api\n */\nView.prototype.setMaxZoom = function(zoom) {\n this.applyOptions_(this.getUpdatedOptions_({maxZoom: zoom}));\n};\n\n\n/**\n * Get the minimum zoom level for the view.\n * @return {number} The minimum zoom level.\n * @api\n */\nView.prototype.getMinZoom = function() {\n return /** @type {number} */ (this.getZoomForResolution(this.maxResolution_));\n};\n\n\n/**\n * Set a new minimum zoom level for the view.\n * @param {number} zoom The minimum zoom level.\n * @api\n */\nView.prototype.setMinZoom = function(zoom) {\n this.applyOptions_(this.getUpdatedOptions_({minZoom: zoom}));\n};\n\n\n/**\n * Get the view projection.\n * @return {module:ol/proj/Projection} The projection of the view.\n * @api\n */\nView.prototype.getProjection = function() {\n return this.projection_;\n};\n\n\n/**\n * Get the view resolution.\n * @return {number|undefined} The resolution of the view.\n * @observable\n * @api\n */\nView.prototype.getResolution = function() {\n return /** @type {number|undefined} */ (this.get(ViewProperty.RESOLUTION));\n};\n\n\n/**\n * Get the resolutions for the view. This returns the array of resolutions\n * passed to the constructor of the View, or undefined if none were given.\n * @return {Array.|undefined} The resolutions of the view.\n * @api\n */\nView.prototype.getResolutions = function() {\n return this.resolutions_;\n};\n\n\n/**\n * Get the resolution for a provided extent (in map units) and size (in pixels).\n * @param {module:ol/extent~Extent} extent Extent.\n * @param {module:ol/size~Size=} opt_size Box pixel size.\n * @return {number} The resolution at which the provided extent will render at\n * the given size.\n * @api\n */\nView.prototype.getResolutionForExtent = function(extent, opt_size) {\n const size = opt_size || this.getSizeFromViewport_();\n const xResolution = getWidth(extent) / size[0];\n const yResolution = getHeight(extent) / size[1];\n return Math.max(xResolution, yResolution);\n};\n\n\n/**\n * Return a function that returns a value between 0 and 1 for a\n * resolution. Exponential scaling is assumed.\n * @param {number=} opt_power Power.\n * @return {function(number): number} Resolution for value function.\n */\nView.prototype.getResolutionForValueFunction = function(opt_power) {\n const power = opt_power || 2;\n const maxResolution = this.maxResolution_;\n const minResolution = this.minResolution_;\n const max = Math.log(maxResolution / minResolution) / Math.log(power);\n return (\n /**\n * @param {number} value Value.\n * @return {number} Resolution.\n */\n function(value) {\n const resolution = maxResolution / Math.pow(power, value * max);\n return resolution;\n });\n};\n\n\n/**\n * Get the view rotation.\n * @return {number} The rotation of the view in radians.\n * @observable\n * @api\n */\nView.prototype.getRotation = function() {\n return /** @type {number} */ (this.get(ViewProperty.ROTATION));\n};\n\n\n/**\n * Return a function that returns a resolution for a value between\n * 0 and 1. Exponential scaling is assumed.\n * @param {number=} opt_power Power.\n * @return {function(number): number} Value for resolution function.\n */\nView.prototype.getValueForResolutionFunction = function(opt_power) {\n const power = opt_power || 2;\n const maxResolution = this.maxResolution_;\n const minResolution = this.minResolution_;\n const max = Math.log(maxResolution / minResolution) / Math.log(power);\n return (\n /**\n * @param {number} resolution Resolution.\n * @return {number} Value.\n */\n function(resolution) {\n const value = (Math.log(maxResolution / resolution) / Math.log(power)) / max;\n return value;\n });\n};\n\n\n/**\n * @return {module:ol/View~State} View state.\n */\nView.prototype.getState = function() {\n const center = /** @type {module:ol/coordinate~Coordinate} */ (this.getCenter());\n const projection = this.getProjection();\n const resolution = /** @type {number} */ (this.getResolution());\n const rotation = this.getRotation();\n return (\n /** @type {module:ol/View~State} */ ({\n center: center.slice(),\n projection: projection !== undefined ? projection : null,\n resolution: resolution,\n rotation: rotation,\n zoom: this.getZoom()\n })\n );\n};\n\n\n/**\n * Get the current zoom level. If you configured your view with a resolutions\n * array (this is rare), this method may return non-integer zoom levels (so\n * the zoom level is not safe to use as an index into a resolutions array).\n * @return {number|undefined} Zoom.\n * @api\n */\nView.prototype.getZoom = function() {\n let zoom;\n const resolution = this.getResolution();\n if (resolution !== undefined) {\n zoom = this.getZoomForResolution(resolution);\n }\n return zoom;\n};\n\n\n/**\n * Get the zoom level for a resolution.\n * @param {number} resolution The resolution.\n * @return {number|undefined} The zoom level for the provided resolution.\n * @api\n */\nView.prototype.getZoomForResolution = function(resolution) {\n let offset = this.minZoom_ || 0;\n let max, zoomFactor;\n if (this.resolutions_) {\n const nearest = linearFindNearest(this.resolutions_, resolution, 1);\n offset = nearest;\n max = this.resolutions_[nearest];\n if (nearest == this.resolutions_.length - 1) {\n zoomFactor = 2;\n } else {\n zoomFactor = max / this.resolutions_[nearest + 1];\n }\n } else {\n max = this.maxResolution_;\n zoomFactor = this.zoomFactor_;\n }\n return offset + Math.log(max / resolution) / Math.log(zoomFactor);\n};\n\n\n/**\n * Get the resolution for a zoom level.\n * @param {number} zoom Zoom level.\n * @return {number} The view resolution for the provided zoom level.\n * @api\n */\nView.prototype.getResolutionForZoom = function(zoom) {\n return /** @type {number} */ (this.constrainResolution(\n this.maxResolution_, zoom - this.minZoom_, 0));\n};\n\n\n/**\n * Fit the given geometry or extent based on the given map size and border.\n * The size is pixel dimensions of the box to fit the extent into.\n * In most cases you will want to use the map size, that is `map.getSize()`.\n * Takes care of the map angle.\n * @param {module:ol/geom/SimpleGeometry|module:ol/extent~Extent} geometryOrExtent The geometry or\n * extent to fit the view to.\n * @param {module:ol/View~FitOptions=} opt_options Options.\n * @api\n */\nView.prototype.fit = function(geometryOrExtent, opt_options) {\n const options = opt_options || {};\n let size = options.size;\n if (!size) {\n size = this.getSizeFromViewport_();\n }\n /** @type {module:ol/geom/SimpleGeometry} */\n let geometry;\n if (!(geometryOrExtent instanceof SimpleGeometry)) {\n assert(Array.isArray(geometryOrExtent),\n 24); // Invalid extent or geometry provided as `geometry`\n assert(!isEmpty(geometryOrExtent),\n 25); // Cannot fit empty extent provided as `geometry`\n geometry = polygonFromExtent(geometryOrExtent);\n } else if (geometryOrExtent.getType() === GeometryType.CIRCLE) {\n geometryOrExtent = geometryOrExtent.getExtent();\n geometry = polygonFromExtent(geometryOrExtent);\n geometry.rotate(this.getRotation(), getCenter(geometryOrExtent));\n } else {\n geometry = geometryOrExtent;\n }\n\n const padding = options.padding !== undefined ? options.padding : [0, 0, 0, 0];\n const constrainResolution = options.constrainResolution !== undefined ?\n options.constrainResolution : true;\n const nearest = options.nearest !== undefined ? options.nearest : false;\n let minResolution;\n if (options.minResolution !== undefined) {\n minResolution = options.minResolution;\n } else if (options.maxZoom !== undefined) {\n minResolution = this.constrainResolution(\n this.maxResolution_, options.maxZoom - this.minZoom_, 0);\n } else {\n minResolution = 0;\n }\n const coords = geometry.getFlatCoordinates();\n\n // calculate rotated extent\n const rotation = this.getRotation();\n const cosAngle = Math.cos(-rotation);\n let sinAngle = Math.sin(-rotation);\n let minRotX = +Infinity;\n let minRotY = +Infinity;\n let maxRotX = -Infinity;\n let maxRotY = -Infinity;\n const stride = geometry.getStride();\n for (let i = 0, ii = coords.length; i < ii; i += stride) {\n const rotX = coords[i] * cosAngle - coords[i + 1] * sinAngle;\n const rotY = coords[i] * sinAngle + coords[i + 1] * cosAngle;\n minRotX = Math.min(minRotX, rotX);\n minRotY = Math.min(minRotY, rotY);\n maxRotX = Math.max(maxRotX, rotX);\n maxRotY = Math.max(maxRotY, rotY);\n }\n\n // calculate resolution\n let resolution = this.getResolutionForExtent(\n [minRotX, minRotY, maxRotX, maxRotY],\n [size[0] - padding[1] - padding[3], size[1] - padding[0] - padding[2]]);\n resolution = isNaN(resolution) ? minResolution :\n Math.max(resolution, minResolution);\n if (constrainResolution) {\n let constrainedResolution = this.constrainResolution(resolution, 0, 0);\n if (!nearest && constrainedResolution < resolution) {\n constrainedResolution = this.constrainResolution(\n constrainedResolution, -1, 0);\n }\n resolution = constrainedResolution;\n }\n\n // calculate center\n sinAngle = -sinAngle; // go back to original rotation\n let centerRotX = (minRotX + maxRotX) / 2;\n let centerRotY = (minRotY + maxRotY) / 2;\n centerRotX += (padding[1] - padding[3]) / 2 * resolution;\n centerRotY += (padding[0] - padding[2]) / 2 * resolution;\n const centerX = centerRotX * cosAngle - centerRotY * sinAngle;\n const centerY = centerRotY * cosAngle + centerRotX * sinAngle;\n const center = [centerX, centerY];\n const callback = options.callback ? options.callback : UNDEFINED;\n\n if (options.duration !== undefined) {\n this.animate({\n resolution: resolution,\n center: center,\n duration: options.duration,\n easing: options.easing\n }, callback);\n } else {\n this.setResolution(resolution);\n this.setCenter(center);\n setTimeout(callback.bind(undefined, true), 0);\n }\n};\n\n\n/**\n * Center on coordinate and view position.\n * @param {module:ol/coordinate~Coordinate} coordinate Coordinate.\n * @param {module:ol/size~Size} size Box pixel size.\n * @param {module:ol~Pixel} position Position on the view to center on.\n * @api\n */\nView.prototype.centerOn = function(coordinate, size, position) {\n // calculate rotated position\n const rotation = this.getRotation();\n const cosAngle = Math.cos(-rotation);\n let sinAngle = Math.sin(-rotation);\n let rotX = coordinate[0] * cosAngle - coordinate[1] * sinAngle;\n let rotY = coordinate[1] * cosAngle + coordinate[0] * sinAngle;\n const resolution = this.getResolution();\n rotX += (size[0] / 2 - position[0]) * resolution;\n rotY += (position[1] - size[1] / 2) * resolution;\n\n // go back to original angle\n sinAngle = -sinAngle; // go back to original rotation\n const centerX = rotX * cosAngle - rotY * sinAngle;\n const centerY = rotY * cosAngle + rotX * sinAngle;\n\n this.setCenter([centerX, centerY]);\n};\n\n\n/**\n * @return {boolean} Is defined.\n */\nView.prototype.isDef = function() {\n return !!this.getCenter() && this.getResolution() !== undefined;\n};\n\n\n/**\n * Rotate the view around a given coordinate.\n * @param {number} rotation New rotation value for the view.\n * @param {module:ol/coordinate~Coordinate=} opt_anchor The rotation center.\n * @api\n */\nView.prototype.rotate = function(rotation, opt_anchor) {\n if (opt_anchor !== undefined) {\n const center = this.calculateCenterRotate(rotation, opt_anchor);\n this.setCenter(center);\n }\n this.setRotation(rotation);\n};\n\n\n/**\n * Set the center of the current view.\n * @param {module:ol/coordinate~Coordinate|undefined} center The center of the view.\n * @observable\n * @api\n */\nView.prototype.setCenter = function(center) {\n this.set(ViewProperty.CENTER, center);\n if (this.getAnimating()) {\n this.cancelAnimations();\n }\n};\n\n\n/**\n * @param {module:ol/ViewHint} hint Hint.\n * @param {number} delta Delta.\n * @return {number} New value.\n */\nView.prototype.setHint = function(hint, delta) {\n this.hints_[hint] += delta;\n this.changed();\n return this.hints_[hint];\n};\n\n\n/**\n * Set the resolution for this view.\n * @param {number|undefined} resolution The resolution of the view.\n * @observable\n * @api\n */\nView.prototype.setResolution = function(resolution) {\n this.set(ViewProperty.RESOLUTION, resolution);\n if (this.getAnimating()) {\n this.cancelAnimations();\n }\n};\n\n\n/**\n * Set the rotation for this view.\n * @param {number} rotation The rotation of the view in radians.\n * @observable\n * @api\n */\nView.prototype.setRotation = function(rotation) {\n this.set(ViewProperty.ROTATION, rotation);\n if (this.getAnimating()) {\n this.cancelAnimations();\n }\n};\n\n\n/**\n * Zoom to a specific zoom level.\n * @param {number} zoom Zoom level.\n * @api\n */\nView.prototype.setZoom = function(zoom) {\n this.setResolution(this.getResolutionForZoom(zoom));\n};\n\n\n/**\n * @param {module:ol/View~ViewOptions} options View options.\n * @return {module:ol/centerconstraint~Type} The constraint.\n */\nexport function createCenterConstraint(options) {\n if (options.extent !== undefined) {\n return createExtent(options.extent);\n } else {\n return centerNone;\n }\n}\n\n\n/**\n * @param {module:ol/View~ViewOptions} options View options.\n * @return {{constraint: module:ol/resolutionconstraint~Type, maxResolution: number,\n * minResolution: number, minZoom: number, zoomFactor: number}} The constraint.\n */\nexport function createResolutionConstraint(options) {\n let resolutionConstraint;\n let maxResolution;\n let minResolution;\n\n // TODO: move these to be ol constants\n // see https://github.com/openlayers/openlayers/issues/2076\n const defaultMaxZoom = 28;\n const defaultZoomFactor = 2;\n\n let minZoom = options.minZoom !== undefined ?\n options.minZoom : DEFAULT_MIN_ZOOM;\n\n let maxZoom = options.maxZoom !== undefined ?\n options.maxZoom : defaultMaxZoom;\n\n const zoomFactor = options.zoomFactor !== undefined ?\n options.zoomFactor : defaultZoomFactor;\n\n if (options.resolutions !== undefined) {\n const resolutions = options.resolutions;\n maxResolution = resolutions[minZoom];\n minResolution = resolutions[maxZoom] !== undefined ?\n resolutions[maxZoom] : resolutions[resolutions.length - 1];\n resolutionConstraint = createSnapToResolutions(\n resolutions);\n } else {\n // calculate the default min and max resolution\n const projection = createProjection(options.projection, 'EPSG:3857');\n const extent = projection.getExtent();\n const size = !extent ?\n // use an extent that can fit the whole world if need be\n 360 * METERS_PER_UNIT[Units.DEGREES] /\n projection.getMetersPerUnit() :\n Math.max(getWidth(extent), getHeight(extent));\n\n const defaultMaxResolution = size / DEFAULT_TILE_SIZE / Math.pow(\n defaultZoomFactor, DEFAULT_MIN_ZOOM);\n\n const defaultMinResolution = defaultMaxResolution / Math.pow(\n defaultZoomFactor, defaultMaxZoom - DEFAULT_MIN_ZOOM);\n\n // user provided maxResolution takes precedence\n maxResolution = options.maxResolution;\n if (maxResolution !== undefined) {\n minZoom = 0;\n } else {\n maxResolution = defaultMaxResolution / Math.pow(zoomFactor, minZoom);\n }\n\n // user provided minResolution takes precedence\n minResolution = options.minResolution;\n if (minResolution === undefined) {\n if (options.maxZoom !== undefined) {\n if (options.maxResolution !== undefined) {\n minResolution = maxResolution / Math.pow(zoomFactor, maxZoom);\n } else {\n minResolution = defaultMaxResolution / Math.pow(zoomFactor, maxZoom);\n }\n } else {\n minResolution = defaultMinResolution;\n }\n }\n\n // given discrete zoom levels, minResolution may be different than provided\n maxZoom = minZoom + Math.floor(\n Math.log(maxResolution / minResolution) / Math.log(zoomFactor));\n minResolution = maxResolution / Math.pow(zoomFactor, maxZoom - minZoom);\n\n resolutionConstraint = createSnapToPower(\n zoomFactor, maxResolution, maxZoom - minZoom);\n }\n return {constraint: resolutionConstraint, maxResolution: maxResolution,\n minResolution: minResolution, minZoom: minZoom, zoomFactor: zoomFactor};\n}\n\n\n/**\n * @param {module:ol/View~ViewOptions} options View options.\n * @return {module:ol/rotationconstraint~Type} Rotation constraint.\n */\nexport function createRotationConstraint(options) {\n const enableRotation = options.enableRotation !== undefined ?\n options.enableRotation : true;\n if (enableRotation) {\n const constrainRotation = options.constrainRotation;\n if (constrainRotation === undefined || constrainRotation === true) {\n return createSnapToZero();\n } else if (constrainRotation === false) {\n return rotationNone;\n } else if (typeof constrainRotation === 'number') {\n return createSnapToN(constrainRotation);\n } else {\n return rotationNone;\n }\n } else {\n return disable;\n }\n}\n\n\n/**\n * Determine if an animation involves no view change.\n * @param {module:ol/View~Animation} animation The animation.\n * @return {boolean} The animation involves no view change.\n */\nexport function isNoopAnimation(animation) {\n if (animation.sourceCenter && animation.targetCenter) {\n if (!coordinatesEqual(animation.sourceCenter, animation.targetCenter)) {\n return false;\n }\n }\n if (animation.sourceResolution !== animation.targetResolution) {\n return false;\n }\n if (animation.sourceRotation !== animation.targetRotation) {\n return false;\n }\n return true;\n}\n\nexport default View;\n","/**\n * @module ol/resolutionconstraint\n */\nimport {linearFindNearest} from './array.js';\nimport {clamp} from './math.js';\n\n\n/**\n * @typedef {function((number|undefined), number, number): (number|undefined)} Type\n */\n\n\n/**\n * @param {Array.} resolutions Resolutions.\n * @return {module:ol/resolutionconstraint~Type} Zoom function.\n */\nexport function createSnapToResolutions(resolutions) {\n return (\n /**\n * @param {number|undefined} resolution Resolution.\n * @param {number} delta Delta.\n * @param {number} direction Direction.\n * @return {number|undefined} Resolution.\n */\n function(resolution, delta, direction) {\n if (resolution !== undefined) {\n let z = linearFindNearest(resolutions, resolution, direction);\n z = clamp(z + delta, 0, resolutions.length - 1);\n const index = Math.floor(z);\n if (z != index && index < resolutions.length - 1) {\n const power = resolutions[index] / resolutions[index + 1];\n return resolutions[index] / Math.pow(power, z - index);\n } else {\n return resolutions[index];\n }\n } else {\n return undefined;\n }\n }\n );\n}\n\n\n/**\n * @param {number} power Power.\n * @param {number} maxResolution Maximum resolution.\n * @param {number=} opt_maxLevel Maximum level.\n * @return {module:ol/resolutionconstraint~Type} Zoom function.\n */\nexport function createSnapToPower(power, maxResolution, opt_maxLevel) {\n return (\n /**\n * @param {number|undefined} resolution Resolution.\n * @param {number} delta Delta.\n * @param {number} direction Direction.\n * @return {number|undefined} Resolution.\n */\n function(resolution, delta, direction) {\n if (resolution !== undefined) {\n const offset = -direction / 2 + 0.5;\n const oldLevel = Math.floor(\n Math.log(maxResolution / resolution) / Math.log(power) + offset);\n let newLevel = Math.max(oldLevel + delta, 0);\n if (opt_maxLevel !== undefined) {\n newLevel = Math.min(newLevel, opt_maxLevel);\n }\n return maxResolution / Math.pow(power, newLevel);\n } else {\n return undefined;\n }\n });\n}\n","/**\n * @module ol/layer/Property\n */\n\n/**\n * @enum {string}\n */\nexport default {\n OPACITY: 'opacity',\n VISIBLE: 'visible',\n EXTENT: 'extent',\n Z_INDEX: 'zIndex',\n MAX_RESOLUTION: 'maxResolution',\n MIN_RESOLUTION: 'minResolution',\n SOURCE: 'source'\n};\n","/**\n * @module ol/layer/Base\n */\nimport {inherits} from '../util.js';\nimport BaseObject from '../Object.js';\nimport LayerProperty from '../layer/Property.js';\nimport {clamp} from '../math.js';\nimport {assign} from '../obj.js';\n\n\n/**\n * @typedef {Object} Options\n * @property {number} [opacity=1] Opacity (0, 1).\n * @property {boolean} [visible=true] Visibility.\n * @property {module:ol/extent~Extent} [extent] The bounding extent for layer rendering. The layer will not be\n * rendered outside of this extent.\n * @property {number} [zIndex=0] The z-index for layer rendering. At rendering time, the layers\n * will be ordered, first by Z-index and then by position.\n * @property {number} [minResolution] The minimum resolution (inclusive) at which this layer will be\n * visible.\n * @property {number} [maxResolution] The maximum resolution (exclusive) below which this layer will\n * be visible.\n */\n\n\n/**\n * @classdesc\n * Abstract base class; normally only used for creating subclasses and not\n * instantiated in apps.\n * Note that with {@link module:ol/layer/Base} and all its subclasses, any property set in\n * the options is set as a {@link module:ol/Object} property on the layer object, so\n * is observable, and has get/set accessors.\n *\n * @constructor\n * @abstract\n * @extends {module:ol/Object}\n * @param {module:ol/layer/Base~Options} options Layer options.\n * @api\n */\nconst BaseLayer = function(options) {\n\n BaseObject.call(this);\n\n /**\n * @type {Object.}\n */\n const properties = assign({}, options);\n properties[LayerProperty.OPACITY] =\n options.opacity !== undefined ? options.opacity : 1;\n properties[LayerProperty.VISIBLE] =\n options.visible !== undefined ? options.visible : true;\n properties[LayerProperty.Z_INDEX] =\n options.zIndex !== undefined ? options.zIndex : 0;\n properties[LayerProperty.MAX_RESOLUTION] =\n options.maxResolution !== undefined ? options.maxResolution : Infinity;\n properties[LayerProperty.MIN_RESOLUTION] =\n options.minResolution !== undefined ? options.minResolution : 0;\n\n this.setProperties(properties);\n\n /**\n * @type {module:ol/layer/Layer~State}\n * @private\n */\n this.state_ = /** @type {module:ol/layer/Layer~State} */ ({\n layer: /** @type {module:ol/layer/Layer} */ (this),\n managed: true\n });\n\n /**\n * The layer type.\n * @type {module:ol/LayerType}\n * @protected;\n */\n this.type;\n\n};\n\ninherits(BaseLayer, BaseObject);\n\n\n/**\n * Get the layer type (used when creating a layer renderer).\n * @return {module:ol/LayerType} The layer type.\n */\nBaseLayer.prototype.getType = function() {\n return this.type;\n};\n\n\n/**\n * @return {module:ol/layer/Layer~State} Layer state.\n */\nBaseLayer.prototype.getLayerState = function() {\n this.state_.opacity = clamp(this.getOpacity(), 0, 1);\n this.state_.sourceState = this.getSourceState();\n this.state_.visible = this.getVisible();\n this.state_.extent = this.getExtent();\n this.state_.zIndex = this.getZIndex();\n this.state_.maxResolution = this.getMaxResolution();\n this.state_.minResolution = Math.max(this.getMinResolution(), 0);\n\n return this.state_;\n};\n\n\n/**\n * @abstract\n * @param {Array.=} opt_array Array of layers (to be\n * modified in place).\n * @return {Array.} Array of layers.\n */\nBaseLayer.prototype.getLayersArray = function(opt_array) {};\n\n\n/**\n * @abstract\n * @param {Array.=} opt_states Optional list of layer\n * states (to be modified in place).\n * @return {Array.} List of layer states.\n */\nBaseLayer.prototype.getLayerStatesArray = function(opt_states) {};\n\n\n/**\n * Return the {@link module:ol/extent~Extent extent} of the layer or `undefined` if it\n * will be visible regardless of extent.\n * @return {module:ol/extent~Extent|undefined} The layer extent.\n * @observable\n * @api\n */\nBaseLayer.prototype.getExtent = function() {\n return (\n /** @type {module:ol/extent~Extent|undefined} */ (this.get(LayerProperty.EXTENT))\n );\n};\n\n\n/**\n * Return the maximum resolution of the layer.\n * @return {number} The maximum resolution of the layer.\n * @observable\n * @api\n */\nBaseLayer.prototype.getMaxResolution = function() {\n return /** @type {number} */ (this.get(LayerProperty.MAX_RESOLUTION));\n};\n\n\n/**\n * Return the minimum resolution of the layer.\n * @return {number} The minimum resolution of the layer.\n * @observable\n * @api\n */\nBaseLayer.prototype.getMinResolution = function() {\n return /** @type {number} */ (this.get(LayerProperty.MIN_RESOLUTION));\n};\n\n\n/**\n * Return the opacity of the layer (between 0 and 1).\n * @return {number} The opacity of the layer.\n * @observable\n * @api\n */\nBaseLayer.prototype.getOpacity = function() {\n return /** @type {number} */ (this.get(LayerProperty.OPACITY));\n};\n\n\n/**\n * @abstract\n * @return {module:ol/source/State} Source state.\n */\nBaseLayer.prototype.getSourceState = function() {};\n\n\n/**\n * Return the visibility of the layer (`true` or `false`).\n * @return {boolean} The visibility of the layer.\n * @observable\n * @api\n */\nBaseLayer.prototype.getVisible = function() {\n return /** @type {boolean} */ (this.get(LayerProperty.VISIBLE));\n};\n\n\n/**\n * Return the Z-index of the layer, which is used to order layers before\n * rendering. The default Z-index is 0.\n * @return {number} The Z-index of the layer.\n * @observable\n * @api\n */\nBaseLayer.prototype.getZIndex = function() {\n return /** @type {number} */ (this.get(LayerProperty.Z_INDEX));\n};\n\n\n/**\n * Set the extent at which the layer is visible. If `undefined`, the layer\n * will be visible at all extents.\n * @param {module:ol/extent~Extent|undefined} extent The extent of the layer.\n * @observable\n * @api\n */\nBaseLayer.prototype.setExtent = function(extent) {\n this.set(LayerProperty.EXTENT, extent);\n};\n\n\n/**\n * Set the maximum resolution at which the layer is visible.\n * @param {number} maxResolution The maximum resolution of the layer.\n * @observable\n * @api\n */\nBaseLayer.prototype.setMaxResolution = function(maxResolution) {\n this.set(LayerProperty.MAX_RESOLUTION, maxResolution);\n};\n\n\n/**\n * Set the minimum resolution at which the layer is visible.\n * @param {number} minResolution The minimum resolution of the layer.\n * @observable\n * @api\n */\nBaseLayer.prototype.setMinResolution = function(minResolution) {\n this.set(LayerProperty.MIN_RESOLUTION, minResolution);\n};\n\n\n/**\n * Set the opacity of the layer, allowed values range from 0 to 1.\n * @param {number} opacity The opacity of the layer.\n * @observable\n * @api\n */\nBaseLayer.prototype.setOpacity = function(opacity) {\n this.set(LayerProperty.OPACITY, opacity);\n};\n\n\n/**\n * Set the visibility of the layer (`true` or `false`).\n * @param {boolean} visible The visibility of the layer.\n * @observable\n * @api\n */\nBaseLayer.prototype.setVisible = function(visible) {\n this.set(LayerProperty.VISIBLE, visible);\n};\n\n\n/**\n * Set Z-index of the layer, which is used to order layers before rendering.\n * The default Z-index is 0.\n * @param {number} zindex The z-index of the layer.\n * @observable\n * @api\n */\nBaseLayer.prototype.setZIndex = function(zindex) {\n this.set(LayerProperty.Z_INDEX, zindex);\n};\nexport default BaseLayer;\n","/**\n * @module ol/source/State\n */\n\n/**\n * State of the source, one of 'undefined', 'loading', 'ready' or 'error'.\n * @enum {string}\n */\nexport default {\n UNDEFINED: 'undefined',\n LOADING: 'loading',\n READY: 'ready',\n ERROR: 'error'\n};\n","/**\n * @module ol/layer/Group\n */\nimport {getUid, inherits} from '../util.js';\nimport Collection from '../Collection.js';\nimport CollectionEventType from '../CollectionEventType.js';\nimport {getChangeEventType} from '../Object.js';\nimport ObjectEventType from '../ObjectEventType.js';\nimport {assert} from '../asserts.js';\nimport {listen, unlistenByKey} from '../events.js';\nimport EventType from '../events/EventType.js';\nimport {getIntersection} from '../extent.js';\nimport BaseLayer from '../layer/Base.js';\nimport {assign, clear} from '../obj.js';\nimport SourceState from '../source/State.js';\n\n\n/**\n * @typedef {Object} Options\n * @property {number} [opacity=1] Opacity (0, 1).\n * @property {boolean} [visible=true] Visibility.\n * @property {module:ol/extent~Extent} [extent] The bounding extent for layer rendering. The layer will not be\n * rendered outside of this extent.\n * @property {number} [zIndex=0] The z-index for layer rendering. At rendering time, the layers\n * will be ordered, first by Z-index and then by position.\n * @property {number} [minResolution] The minimum resolution (inclusive) at which this layer will be\n * visible.\n * @property {number} [maxResolution] The maximum resolution (exclusive) below which this layer will\n * be visible.\n * @property {(Array.|module:ol/Collection.)} [layers] Child layers.\n */\n\n\n/**\n * @enum {string}\n * @private\n */\nconst Property = {\n LAYERS: 'layers'\n};\n\n\n/**\n * @classdesc\n * A {@link module:ol/Collection~Collection} of layers that are handled together.\n *\n * A generic `change` event is triggered when the group/Collection changes.\n *\n * @constructor\n * @extends {module:ol/layer/Base}\n * @param {module:ol/layer/Group~Options=} opt_options Layer options.\n * @api\n */\nconst LayerGroup = function(opt_options) {\n\n const options = opt_options || {};\n const baseOptions = /** @type {module:ol/layer/Group~Options} */ (assign({}, options));\n delete baseOptions.layers;\n\n let layers = options.layers;\n\n BaseLayer.call(this, baseOptions);\n\n /**\n * @private\n * @type {Array.}\n */\n this.layersListenerKeys_ = [];\n\n /**\n * @private\n * @type {Object.>}\n */\n this.listenerKeys_ = {};\n\n listen(this,\n getChangeEventType(Property.LAYERS),\n this.handleLayersChanged_, this);\n\n if (layers) {\n if (Array.isArray(layers)) {\n layers = new Collection(layers.slice(), {unique: true});\n } else {\n assert(layers instanceof Collection,\n 43); // Expected `layers` to be an array or a `Collection`\n layers = layers;\n }\n } else {\n layers = new Collection(undefined, {unique: true});\n }\n\n this.setLayers(layers);\n\n};\n\ninherits(LayerGroup, BaseLayer);\n\n\n/**\n * @private\n */\nLayerGroup.prototype.handleLayerChange_ = function() {\n this.changed();\n};\n\n\n/**\n * @param {module:ol/events/Event} event Event.\n * @private\n */\nLayerGroup.prototype.handleLayersChanged_ = function(event) {\n this.layersListenerKeys_.forEach(unlistenByKey);\n this.layersListenerKeys_.length = 0;\n\n const layers = this.getLayers();\n this.layersListenerKeys_.push(\n listen(layers, CollectionEventType.ADD, this.handleLayersAdd_, this),\n listen(layers, CollectionEventType.REMOVE, this.handleLayersRemove_, this)\n );\n\n for (const id in this.listenerKeys_) {\n this.listenerKeys_[id].forEach(unlistenByKey);\n }\n clear(this.listenerKeys_);\n\n const layersArray = layers.getArray();\n for (let i = 0, ii = layersArray.length; i < ii; i++) {\n const layer = layersArray[i];\n this.listenerKeys_[getUid(layer).toString()] = [\n listen(layer, ObjectEventType.PROPERTYCHANGE, this.handleLayerChange_, this),\n listen(layer, EventType.CHANGE, this.handleLayerChange_, this)\n ];\n }\n\n this.changed();\n};\n\n\n/**\n * @param {module:ol/Collection~CollectionEvent} collectionEvent CollectionEvent.\n * @private\n */\nLayerGroup.prototype.handleLayersAdd_ = function(collectionEvent) {\n const layer = /** @type {module:ol/layer/Base} */ (collectionEvent.element);\n const key = getUid(layer).toString();\n this.listenerKeys_[key] = [\n listen(layer, ObjectEventType.PROPERTYCHANGE, this.handleLayerChange_, this),\n listen(layer, EventType.CHANGE, this.handleLayerChange_, this)\n ];\n this.changed();\n};\n\n\n/**\n * @param {module:ol/Collection~CollectionEvent} collectionEvent CollectionEvent.\n * @private\n */\nLayerGroup.prototype.handleLayersRemove_ = function(collectionEvent) {\n const layer = /** @type {module:ol/layer/Base} */ (collectionEvent.element);\n const key = getUid(layer).toString();\n this.listenerKeys_[key].forEach(unlistenByKey);\n delete this.listenerKeys_[key];\n this.changed();\n};\n\n\n/**\n * Returns the {@link module:ol/Collection collection} of {@link module:ol/layer/Layer~Layer layers}\n * in this group.\n * @return {!module:ol/Collection.} Collection of\n * {@link module:ol/layer/Base layers} that are part of this group.\n * @observable\n * @api\n */\nLayerGroup.prototype.getLayers = function() {\n return (\n /** @type {!module:ol/Collection.} */ (this.get(Property.LAYERS))\n );\n};\n\n\n/**\n * Set the {@link module:ol/Collection collection} of {@link module:ol/layer/Layer~Layer layers}\n * in this group.\n * @param {!module:ol/Collection.} layers Collection of\n * {@link module:ol/layer/Base layers} that are part of this group.\n * @observable\n * @api\n */\nLayerGroup.prototype.setLayers = function(layers) {\n this.set(Property.LAYERS, layers);\n};\n\n\n/**\n * @inheritDoc\n */\nLayerGroup.prototype.getLayersArray = function(opt_array) {\n const array = opt_array !== undefined ? opt_array : [];\n this.getLayers().forEach(function(layer) {\n layer.getLayersArray(array);\n });\n return array;\n};\n\n\n/**\n * @inheritDoc\n */\nLayerGroup.prototype.getLayerStatesArray = function(opt_states) {\n const states = opt_states !== undefined ? opt_states : [];\n\n const pos = states.length;\n\n this.getLayers().forEach(function(layer) {\n layer.getLayerStatesArray(states);\n });\n\n const ownLayerState = this.getLayerState();\n for (let i = pos, ii = states.length; i < ii; i++) {\n const layerState = states[i];\n layerState.opacity *= ownLayerState.opacity;\n layerState.visible = layerState.visible && ownLayerState.visible;\n layerState.maxResolution = Math.min(\n layerState.maxResolution, ownLayerState.maxResolution);\n layerState.minResolution = Math.max(\n layerState.minResolution, ownLayerState.minResolution);\n if (ownLayerState.extent !== undefined) {\n if (layerState.extent !== undefined) {\n layerState.extent = getIntersection(layerState.extent, ownLayerState.extent);\n } else {\n layerState.extent = ownLayerState.extent;\n }\n }\n }\n\n return states;\n};\n\n\n/**\n * @inheritDoc\n */\nLayerGroup.prototype.getSourceState = function() {\n return SourceState.READY;\n};\n\nexport default LayerGroup;\n","/**\n * @module ol/size\n */\n\n\n/**\n * An array of numbers representing a size: `[width, height]`.\n * @typedef {Array.} Size\n * @api\n */\n\n\n/**\n * Returns a buffered size.\n * @param {module:ol/size~Size} size Size.\n * @param {number} num The amount by which to buffer.\n * @param {module:ol/size~Size=} opt_size Optional reusable size array.\n * @return {module:ol/size~Size} The buffered size.\n */\nexport function buffer(size, num, opt_size) {\n if (opt_size === undefined) {\n opt_size = [0, 0];\n }\n opt_size[0] = size[0] + 2 * num;\n opt_size[1] = size[1] + 2 * num;\n return opt_size;\n}\n\n\n/**\n * Determines if a size has a positive area.\n * @param {module:ol/size~Size} size The size to test.\n * @return {boolean} The size has a positive area.\n */\nexport function hasArea(size) {\n return size[0] > 0 && size[1] > 0;\n}\n\n\n/**\n * Returns a size scaled by a ratio. The result will be an array of integers.\n * @param {module:ol/size~Size} size Size.\n * @param {number} ratio Ratio.\n * @param {module:ol/size~Size=} opt_size Optional reusable size array.\n * @return {module:ol/size~Size} The scaled size.\n */\nexport function scale(size, ratio, opt_size) {\n if (opt_size === undefined) {\n opt_size = [0, 0];\n }\n opt_size[0] = (size[0] * ratio + 0.5) | 0;\n opt_size[1] = (size[1] * ratio + 0.5) | 0;\n return opt_size;\n}\n\n\n/**\n * Returns an `module:ol/size~Size` array for the passed in number (meaning: square) or\n * `module:ol/size~Size` array.\n * (meaning: non-square),\n * @param {number|module:ol/size~Size} size Width and height.\n * @param {module:ol/size~Size=} opt_size Optional reusable size array.\n * @return {module:ol/size~Size} Size.\n * @api\n */\nexport function toSize(size, opt_size) {\n if (Array.isArray(size)) {\n return size;\n } else {\n if (opt_size === undefined) {\n opt_size = [size, size];\n } else {\n opt_size[0] = opt_size[1] = /** @type {number} */ (size);\n }\n return opt_size;\n }\n}\n","/**\n * @module ol/PluggableMap\n */\nimport {getUid, inherits} from './util.js';\nimport Collection from './Collection.js';\nimport CollectionEventType from './CollectionEventType.js';\nimport MapBrowserEvent from './MapBrowserEvent.js';\nimport MapBrowserEventHandler from './MapBrowserEventHandler.js';\nimport MapBrowserEventType from './MapBrowserEventType.js';\nimport MapEvent from './MapEvent.js';\nimport MapEventType from './MapEventType.js';\nimport MapProperty from './MapProperty.js';\nimport BaseObject, {getChangeEventType} from './Object.js';\nimport ObjectEventType from './ObjectEventType.js';\nimport TileQueue from './TileQueue.js';\nimport View from './View.js';\nimport ViewHint from './ViewHint.js';\nimport {assert} from './asserts.js';\nimport {removeNode} from './dom.js';\nimport {listen, unlistenByKey, unlisten} from './events.js';\nimport {stopPropagation} from './events/Event.js';\nimport EventType from './events/EventType.js';\nimport {createEmpty, clone, createOrUpdateEmpty, equals, getForViewAndSize, isEmpty} from './extent.js';\nimport {TRUE} from './functions.js';\nimport {DEVICE_PIXEL_RATIO, TOUCH} from './has.js';\nimport LayerGroup from './layer/Group.js';\nimport {hasArea} from './size.js';\nimport {DROP} from './structs/PriorityQueue.js';\nimport {create as createTransform, apply as applyTransform} from './transform.js';\n\n\n/**\n * State of the current frame. Only `pixelRatio`, `time` and `viewState` should\n * be used in applications.\n * @typedef {Object} FrameState\n * @property {number} pixelRatio The pixel ratio of the frame.\n * @property {number} time The time when rendering of the frame was requested.\n * @property {module:ol/View~State} viewState The state of the current view.\n * @property {boolean} animate\n * @property {module:ol/transform~Transform} coordinateToPixelTransform\n * @property {null|module:ol/extent~Extent} extent\n * @property {module:ol/coordinate~Coordinate} focus\n * @property {number} index\n * @property {Object.} layerStates\n * @property {Array.} layerStatesArray\n * @property {module:ol/transform~Transform} pixelToCoordinateTransform\n * @property {Array.} postRenderFunctions\n * @property {module:ol/size~Size} size\n * @property {!Object.} skippedFeatureUids\n * @property {module:ol/TileQueue} tileQueue\n * @property {Object.>} usedTiles\n * @property {Array.} viewHints\n * @property {!Object.>} wantedTiles\n */\n\n\n/**\n * @typedef {function(module:ol/PluggableMap, ?module:ol/PluggableMap~FrameState): boolean} PostRenderFunction\n */\n\n\n/**\n * @typedef {Object} AtPixelOptions\n * @property {((function(module:ol/layer/Layer): boolean)|undefined)} layerFilter Layer filter\n * function. The filter function will receive one argument, the\n * {@link module:ol/layer/Layer layer-candidate} and it should return a boolean value.\n * Only layers which are visible and for which this function returns `true`\n * will be tested for features. By default, all visible layers will be tested.\n * @property {number} [hitTolerance=0] Hit-detection tolerance in pixels. Pixels\n * inside the radius around the given position will be checked for features. This only\n * works for the canvas renderer and not for WebGL.\n */\n\n\n/**\n * @typedef {Object} MapOptionsInternal\n * @property {module:ol/Collection.} [controls]\n * @property {module:ol/Collection.} [interactions]\n * @property {Element|Document} keyboardEventTarget\n * @property {module:ol/Collection.} overlays\n * @property {Object.} values\n */\n\n\n/**\n * Object literal with config options for the map.\n * @typedef {Object} MapOptions\n * @property {module:ol/Collection.|Array.} [controls]\n * Controls initially added to the map. If not specified,\n * {@link module:ol/control/util~defaults} is used.\n * @property {number} [pixelRatio=window.devicePixelRatio] The ratio between\n * physical pixels and device-independent pixels (dips) on the device.\n * @property {module:ol/Collection.|Array.} [interactions]\n * Interactions that are initially added to the map. If not specified,\n * {@link module:ol/interaction~defaults} is used.\n * @property {Element|Document|string} [keyboardEventTarget] The element to\n * listen to keyboard events on. This determines when the `KeyboardPan` and\n * `KeyboardZoom` interactions trigger. For example, if this option is set to\n * `document` the keyboard interactions will always trigger. If this option is\n * not specified, the element the library listens to keyboard events on is the\n * map target (i.e. the user-provided div for the map). If this is not\n * `document`, the target element needs to be focused for key events to be\n * emitted, requiring that the target element has a `tabindex` attribute.\n * @property {Array.|module:ol/Collection.} [layers]\n * Layers. If this is not defined, a map with no layers will be rendered. Note\n * that layers are rendered in the order supplied, so if you want, for example,\n * a vector layer to appear on top of a tile layer, it must come after the tile\n * layer.\n * @property {number} [maxTilesLoading=16] Maximum number tiles to load\n * simultaneously.\n * @property {boolean} [loadTilesWhileAnimating=false] When set to `true`, tiles\n * will be loaded during animations. This may improve the user experience, but\n * can also make animations stutter on devices with slow memory.\n * @property {boolean} [loadTilesWhileInteracting=false] When set to `true`,\n * tiles will be loaded while interacting with the map. This may improve the\n * user experience, but can also make map panning and zooming choppy on devices\n * with slow memory.\n * @property {number} [moveTolerance=1] The minimum distance in pixels the\n * cursor must move to be detected as a map move event instead of a click.\n * Increasing this value can make it easier to click on the map.\n * @property {module:ol/Collection.|Array.} [overlays]\n * Overlays initially added to the map. By default, no overlays are added.\n * @property {Element|string} [target] The container for the map, either the\n * element itself or the `id` of the element. If not specified at construction\n * time, {@link module:ol/Map~Map#setTarget} must be called for the map to be\n * rendered.\n * @property {module:ol/View} [view] The map's view. No layer sources will be\n * fetched unless this is specified at construction time or through\n * {@link module:ol/Map~Map#setView}.\n */\n\n\n/**\n * @constructor\n * @extends {module:ol/Object}\n * @param {module:ol/PluggableMap~MapOptions} options Map options.\n * @fires module:ol/MapBrowserEvent~MapBrowserEvent\n * @fires module:ol/MapEvent~MapEvent\n * @fires module:ol/render/Event~RenderEvent#postcompose\n * @fires module:ol/render/Event~RenderEvent#precompose\n * @api\n */\nconst PluggableMap = function(options) {\n\n BaseObject.call(this);\n\n const optionsInternal = createOptionsInternal(options);\n\n /**\n * @type {number}\n * @private\n */\n this.maxTilesLoading_ = options.maxTilesLoading !== undefined ? options.maxTilesLoading : 16;\n\n /**\n * @type {boolean}\n * @private\n */\n this.loadTilesWhileAnimating_ =\n options.loadTilesWhileAnimating !== undefined ?\n options.loadTilesWhileAnimating : false;\n\n /**\n * @type {boolean}\n * @private\n */\n this.loadTilesWhileInteracting_ =\n options.loadTilesWhileInteracting !== undefined ?\n options.loadTilesWhileInteracting : false;\n\n /**\n * @private\n * @type {number}\n */\n this.pixelRatio_ = options.pixelRatio !== undefined ?\n options.pixelRatio : DEVICE_PIXEL_RATIO;\n\n /**\n * @private\n * @type {number|undefined}\n */\n this.animationDelayKey_;\n\n /**\n * @private\n */\n this.animationDelay_ = function() {\n this.animationDelayKey_ = undefined;\n this.renderFrame_.call(this, Date.now());\n }.bind(this);\n\n /**\n * @private\n * @type {module:ol/transform~Transform}\n */\n this.coordinateToPixelTransform_ = createTransform();\n\n /**\n * @private\n * @type {module:ol/transform~Transform}\n */\n this.pixelToCoordinateTransform_ = createTransform();\n\n /**\n * @private\n * @type {number}\n */\n this.frameIndex_ = 0;\n\n /**\n * @private\n * @type {?module:ol/PluggableMap~FrameState}\n */\n this.frameState_ = null;\n\n /**\n * The extent at the previous 'moveend' event.\n * @private\n * @type {module:ol/extent~Extent}\n */\n this.previousExtent_ = null;\n\n /**\n * @private\n * @type {?module:ol/events~EventsKey}\n */\n this.viewPropertyListenerKey_ = null;\n\n /**\n * @private\n * @type {?module:ol/events~EventsKey}\n */\n this.viewChangeListenerKey_ = null;\n\n /**\n * @private\n * @type {Array.}\n */\n this.layerGroupPropertyListenerKeys_ = null;\n\n /**\n * @private\n * @type {Element}\n */\n this.viewport_ = document.createElement('DIV');\n this.viewport_.className = 'ol-viewport' + (TOUCH ? ' ol-touch' : '');\n this.viewport_.style.position = 'relative';\n this.viewport_.style.overflow = 'hidden';\n this.viewport_.style.width = '100%';\n this.viewport_.style.height = '100%';\n // prevent page zoom on IE >= 10 browsers\n this.viewport_.style.msTouchAction = 'none';\n this.viewport_.style.touchAction = 'none';\n\n /**\n * @private\n * @type {!Element}\n */\n this.overlayContainer_ = document.createElement('DIV');\n this.overlayContainer_.className = 'ol-overlaycontainer';\n this.viewport_.appendChild(this.overlayContainer_);\n\n /**\n * @private\n * @type {!Element}\n */\n this.overlayContainerStopEvent_ = document.createElement('DIV');\n this.overlayContainerStopEvent_.className = 'ol-overlaycontainer-stopevent';\n const overlayEvents = [\n EventType.CLICK,\n EventType.DBLCLICK,\n EventType.MOUSEDOWN,\n EventType.TOUCHSTART,\n EventType.MSPOINTERDOWN,\n MapBrowserEventType.POINTERDOWN,\n EventType.MOUSEWHEEL,\n EventType.WHEEL\n ];\n for (let i = 0, ii = overlayEvents.length; i < ii; ++i) {\n listen(this.overlayContainerStopEvent_, overlayEvents[i], stopPropagation);\n }\n this.viewport_.appendChild(this.overlayContainerStopEvent_);\n\n /**\n * @private\n * @type {module:ol/MapBrowserEventHandler}\n */\n this.mapBrowserEventHandler_ = new MapBrowserEventHandler(this, options.moveTolerance);\n for (const key in MapBrowserEventType) {\n listen(this.mapBrowserEventHandler_, MapBrowserEventType[key],\n this.handleMapBrowserEvent, this);\n }\n\n /**\n * @private\n * @type {Element|Document}\n */\n this.keyboardEventTarget_ = optionsInternal.keyboardEventTarget;\n\n /**\n * @private\n * @type {Array.}\n */\n this.keyHandlerKeys_ = null;\n\n listen(this.viewport_, EventType.CONTEXTMENU, this.handleBrowserEvent, this);\n listen(this.viewport_, EventType.WHEEL, this.handleBrowserEvent, this);\n listen(this.viewport_, EventType.MOUSEWHEEL, this.handleBrowserEvent, this);\n\n /**\n * @type {module:ol/Collection.}\n * @protected\n */\n this.controls = optionsInternal.controls || new Collection();\n\n /**\n * @type {module:ol/Collection.}\n * @protected\n */\n this.interactions = optionsInternal.interactions || new Collection();\n\n /**\n * @type {module:ol/Collection.}\n * @private\n */\n this.overlays_ = optionsInternal.overlays;\n\n /**\n * A lookup of overlays by id.\n * @private\n * @type {Object.}\n */\n this.overlayIdIndex_ = {};\n\n /**\n * @type {module:ol/renderer/Map}\n * @private\n */\n this.renderer_ = this.createRenderer();\n\n /**\n * @type {function(Event)|undefined}\n * @private\n */\n this.handleResize_;\n\n /**\n * @private\n * @type {module:ol/coordinate~Coordinate}\n */\n this.focus_ = null;\n\n /**\n * @private\n * @type {!Array.}\n */\n this.postRenderFunctions_ = [];\n\n /**\n * @private\n * @type {module:ol/TileQueue}\n */\n this.tileQueue_ = new TileQueue(\n this.getTilePriority.bind(this),\n this.handleTileChange_.bind(this));\n\n /**\n * Uids of features to skip at rendering time.\n * @type {Object.}\n * @private\n */\n this.skippedFeatureUids_ = {};\n\n listen(\n this, getChangeEventType(MapProperty.LAYERGROUP),\n this.handleLayerGroupChanged_, this);\n listen(this, getChangeEventType(MapProperty.VIEW),\n this.handleViewChanged_, this);\n listen(this, getChangeEventType(MapProperty.SIZE),\n this.handleSizeChanged_, this);\n listen(this, getChangeEventType(MapProperty.TARGET),\n this.handleTargetChanged_, this);\n\n // setProperties will trigger the rendering of the map if the map\n // is \"defined\" already.\n this.setProperties(optionsInternal.values);\n\n this.controls.forEach(\n /**\n * @param {module:ol/control/Control} control Control.\n * @this {module:ol/PluggableMap}\n */\n (function(control) {\n control.setMap(this);\n }).bind(this));\n\n listen(this.controls, CollectionEventType.ADD,\n /**\n * @param {module:ol/Collection~CollectionEvent} event CollectionEvent.\n */\n function(event) {\n event.element.setMap(this);\n }, this);\n\n listen(this.controls, CollectionEventType.REMOVE,\n /**\n * @param {module:ol/Collection~CollectionEvent} event CollectionEvent.\n */\n function(event) {\n event.element.setMap(null);\n }, this);\n\n this.interactions.forEach(\n /**\n * @param {module:ol/interaction/Interaction} interaction Interaction.\n * @this {module:ol/PluggableMap}\n */\n (function(interaction) {\n interaction.setMap(this);\n }).bind(this));\n\n listen(this.interactions, CollectionEventType.ADD,\n /**\n * @param {module:ol/Collection~CollectionEvent} event CollectionEvent.\n */\n function(event) {\n event.element.setMap(this);\n }, this);\n\n listen(this.interactions, CollectionEventType.REMOVE,\n /**\n * @param {module:ol/Collection~CollectionEvent} event CollectionEvent.\n */\n function(event) {\n event.element.setMap(null);\n }, this);\n\n this.overlays_.forEach(this.addOverlayInternal_.bind(this));\n\n listen(this.overlays_, CollectionEventType.ADD,\n /**\n * @param {module:ol/Collection~CollectionEvent} event CollectionEvent.\n */\n function(event) {\n this.addOverlayInternal_(/** @type {module:ol/Overlay} */ (event.element));\n }, this);\n\n listen(this.overlays_, CollectionEventType.REMOVE,\n /**\n * @param {module:ol/Collection~CollectionEvent} event CollectionEvent.\n */\n function(event) {\n const overlay = /** @type {module:ol/Overlay} */ (event.element);\n const id = overlay.getId();\n if (id !== undefined) {\n delete this.overlayIdIndex_[id.toString()];\n }\n event.element.setMap(null);\n }, this);\n\n};\n\ninherits(PluggableMap, BaseObject);\n\n\nPluggableMap.prototype.createRenderer = function() {\n throw new Error('Use a map type that has a createRenderer method');\n};\n\n\n/**\n * Add the given control to the map.\n * @param {module:ol/control/Control} control Control.\n * @api\n */\nPluggableMap.prototype.addControl = function(control) {\n this.getControls().push(control);\n};\n\n\n/**\n * Add the given interaction to the map.\n * @param {module:ol/interaction/Interaction} interaction Interaction to add.\n * @api\n */\nPluggableMap.prototype.addInteraction = function(interaction) {\n this.getInteractions().push(interaction);\n};\n\n\n/**\n * Adds the given layer to the top of this map. If you want to add a layer\n * elsewhere in the stack, use `getLayers()` and the methods available on\n * {@link module:ol/Collection~Collection}.\n * @param {module:ol/layer/Base} layer Layer.\n * @api\n */\nPluggableMap.prototype.addLayer = function(layer) {\n const layers = this.getLayerGroup().getLayers();\n layers.push(layer);\n};\n\n\n/**\n * Add the given overlay to the map.\n * @param {module:ol/Overlay} overlay Overlay.\n * @api\n */\nPluggableMap.prototype.addOverlay = function(overlay) {\n this.getOverlays().push(overlay);\n};\n\n\n/**\n * This deals with map's overlay collection changes.\n * @param {module:ol/Overlay} overlay Overlay.\n * @private\n */\nPluggableMap.prototype.addOverlayInternal_ = function(overlay) {\n const id = overlay.getId();\n if (id !== undefined) {\n this.overlayIdIndex_[id.toString()] = overlay;\n }\n overlay.setMap(this);\n};\n\n\n/**\n *\n * @inheritDoc\n */\nPluggableMap.prototype.disposeInternal = function() {\n this.mapBrowserEventHandler_.dispose();\n unlisten(this.viewport_, EventType.CONTEXTMENU, this.handleBrowserEvent, this);\n unlisten(this.viewport_, EventType.WHEEL, this.handleBrowserEvent, this);\n unlisten(this.viewport_, EventType.MOUSEWHEEL, this.handleBrowserEvent, this);\n if (this.handleResize_ !== undefined) {\n removeEventListener(EventType.RESIZE, this.handleResize_, false);\n this.handleResize_ = undefined;\n }\n if (this.animationDelayKey_) {\n cancelAnimationFrame(this.animationDelayKey_);\n this.animationDelayKey_ = undefined;\n }\n this.setTarget(null);\n BaseObject.prototype.disposeInternal.call(this);\n};\n\n\n/**\n * Detect features that intersect a pixel on the viewport, and execute a\n * callback with each intersecting feature. Layers included in the detection can\n * be configured through the `layerFilter` option in `opt_options`.\n * @param {module:ol~Pixel} pixel Pixel.\n * @param {function(this: S, (module:ol/Feature|module:ol/render/Feature),\n * module:ol/layer/Layer): T} callback Feature callback. The callback will be\n * called with two arguments. The first argument is one\n * {@link module:ol/Feature feature} or\n * {@link module:ol/render/Feature render feature} at the pixel, the second is\n * the {@link module:ol/layer/Layer layer} of the feature and will be null for\n * unmanaged layers. To stop detection, callback functions can return a\n * truthy value.\n * @param {module:ol/PluggableMap~AtPixelOptions=} opt_options Optional options.\n * @return {T|undefined} Callback result, i.e. the return value of last\n * callback execution, or the first truthy callback return value.\n * @template S,T\n * @api\n */\nPluggableMap.prototype.forEachFeatureAtPixel = function(pixel, callback, opt_options) {\n if (!this.frameState_) {\n return;\n }\n const coordinate = this.getCoordinateFromPixel(pixel);\n opt_options = opt_options !== undefined ? opt_options : {};\n const hitTolerance = opt_options.hitTolerance !== undefined ?\n opt_options.hitTolerance * this.frameState_.pixelRatio : 0;\n const layerFilter = opt_options.layerFilter !== undefined ?\n opt_options.layerFilter : TRUE;\n return this.renderer_.forEachFeatureAtCoordinate(\n coordinate, this.frameState_, hitTolerance, callback, null,\n layerFilter, null);\n};\n\n\n/**\n * Get all features that intersect a pixel on the viewport.\n * @param {module:ol~Pixel} pixel Pixel.\n * @param {module:ol/PluggableMap~AtPixelOptions=} opt_options Optional options.\n * @return {Array.} The detected features or\n * `null` if none were found.\n * @api\n */\nPluggableMap.prototype.getFeaturesAtPixel = function(pixel, opt_options) {\n let features = null;\n this.forEachFeatureAtPixel(pixel, function(feature) {\n if (!features) {\n features = [];\n }\n features.push(feature);\n }, opt_options);\n return features;\n};\n\n/**\n * Detect layers that have a color value at a pixel on the viewport, and\n * execute a callback with each matching layer. Layers included in the\n * detection can be configured through `opt_layerFilter`.\n * @param {module:ol~Pixel} pixel Pixel.\n * @param {function(this: S, module:ol/layer/Layer, (Uint8ClampedArray|Uint8Array)): T} callback\n * Layer callback. This callback will receive two arguments: first is the\n * {@link module:ol/layer/Layer layer}, second argument is an array representing\n * [R, G, B, A] pixel values (0 - 255) and will be `null` for layer types\n * that do not currently support this argument. To stop detection, callback\n * functions can return a truthy value.\n * @param {module:ol/PluggableMap~AtPixelOptions=} opt_options Configuration options.\n * @return {T|undefined} Callback result, i.e. the return value of last\n * callback execution, or the first truthy callback return value.\n * @template S,T\n * @api\n */\nPluggableMap.prototype.forEachLayerAtPixel = function(pixel, callback, opt_options) {\n if (!this.frameState_) {\n return;\n }\n const options = opt_options || {};\n const hitTolerance = options.hitTolerance !== undefined ?\n opt_options.hitTolerance * this.frameState_.pixelRatio : 0;\n const layerFilter = options.layerFilter || TRUE;\n return this.renderer_.forEachLayerAtPixel(\n pixel, this.frameState_, hitTolerance, callback, null, layerFilter, null);\n};\n\n\n/**\n * Detect if features intersect a pixel on the viewport. Layers included in the\n * detection can be configured through `opt_layerFilter`.\n * @param {module:ol~Pixel} pixel Pixel.\n * @param {module:ol/PluggableMap~AtPixelOptions=} opt_options Optional options.\n * @return {boolean} Is there a feature at the given pixel?\n * @template U\n * @api\n */\nPluggableMap.prototype.hasFeatureAtPixel = function(pixel, opt_options) {\n if (!this.frameState_) {\n return false;\n }\n const coordinate = this.getCoordinateFromPixel(pixel);\n opt_options = opt_options !== undefined ? opt_options : {};\n const layerFilter = opt_options.layerFilter !== undefined ? opt_options.layerFilter : TRUE;\n const hitTolerance = opt_options.hitTolerance !== undefined ?\n opt_options.hitTolerance * this.frameState_.pixelRatio : 0;\n return this.renderer_.hasFeatureAtCoordinate(\n coordinate, this.frameState_, hitTolerance, layerFilter, null);\n};\n\n\n/**\n * Returns the coordinate in view projection for a browser event.\n * @param {Event} event Event.\n * @return {module:ol/coordinate~Coordinate} Coordinate.\n * @api\n */\nPluggableMap.prototype.getEventCoordinate = function(event) {\n return this.getCoordinateFromPixel(this.getEventPixel(event));\n};\n\n\n/**\n * Returns the map pixel position for a browser event relative to the viewport.\n * @param {Event} event Event.\n * @return {module:ol~Pixel} Pixel.\n * @api\n */\nPluggableMap.prototype.getEventPixel = function(event) {\n const viewportPosition = this.viewport_.getBoundingClientRect();\n const eventPosition = event.changedTouches ? event.changedTouches[0] : event;\n return [\n eventPosition.clientX - viewportPosition.left,\n eventPosition.clientY - viewportPosition.top\n ];\n};\n\n\n/**\n * Get the target in which this map is rendered.\n * Note that this returns what is entered as an option or in setTarget:\n * if that was an element, it returns an element; if a string, it returns that.\n * @return {Element|string|undefined} The Element or id of the Element that the\n * map is rendered in.\n * @observable\n * @api\n */\nPluggableMap.prototype.getTarget = function() {\n return /** @type {Element|string|undefined} */ (this.get(MapProperty.TARGET));\n};\n\n\n/**\n * Get the DOM element into which this map is rendered. In contrast to\n * `getTarget` this method always return an `Element`, or `null` if the\n * map has no target.\n * @return {Element} The element that the map is rendered in.\n * @api\n */\nPluggableMap.prototype.getTargetElement = function() {\n const target = this.getTarget();\n if (target !== undefined) {\n return typeof target === 'string' ? document.getElementById(target) : target;\n } else {\n return null;\n }\n};\n\n\n/**\n * Get the coordinate for a given pixel. This returns a coordinate in the\n * map view projection.\n * @param {module:ol~Pixel} pixel Pixel position in the map viewport.\n * @return {module:ol/coordinate~Coordinate} The coordinate for the pixel position.\n * @api\n */\nPluggableMap.prototype.getCoordinateFromPixel = function(pixel) {\n const frameState = this.frameState_;\n if (!frameState) {\n return null;\n } else {\n return applyTransform(frameState.pixelToCoordinateTransform, pixel.slice());\n }\n};\n\n\n/**\n * Get the map controls. Modifying this collection changes the controls\n * associated with the map.\n * @return {module:ol/Collection.} Controls.\n * @api\n */\nPluggableMap.prototype.getControls = function() {\n return this.controls;\n};\n\n\n/**\n * Get the map overlays. Modifying this collection changes the overlays\n * associated with the map.\n * @return {module:ol/Collection.} Overlays.\n * @api\n */\nPluggableMap.prototype.getOverlays = function() {\n return this.overlays_;\n};\n\n\n/**\n * Get an overlay by its identifier (the value returned by overlay.getId()).\n * Note that the index treats string and numeric identifiers as the same. So\n * `map.getOverlayById(2)` will return an overlay with id `'2'` or `2`.\n * @param {string|number} id Overlay identifier.\n * @return {module:ol/Overlay} Overlay.\n * @api\n */\nPluggableMap.prototype.getOverlayById = function(id) {\n const overlay = this.overlayIdIndex_[id.toString()];\n return overlay !== undefined ? overlay : null;\n};\n\n\n/**\n * Get the map interactions. Modifying this collection changes the interactions\n * associated with the map.\n *\n * Interactions are used for e.g. pan, zoom and rotate.\n * @return {module:ol/Collection.} Interactions.\n * @api\n */\nPluggableMap.prototype.getInteractions = function() {\n return this.interactions;\n};\n\n\n/**\n * Get the layergroup associated with this map.\n * @return {module:ol/layer/Group} A layer group containing the layers in this map.\n * @observable\n * @api\n */\nPluggableMap.prototype.getLayerGroup = function() {\n return (\n /** @type {module:ol/layer/Group} */ (this.get(MapProperty.LAYERGROUP))\n );\n};\n\n\n/**\n * Get the collection of layers associated with this map.\n * @return {!module:ol/Collection.} Layers.\n * @api\n */\nPluggableMap.prototype.getLayers = function() {\n const layers = this.getLayerGroup().getLayers();\n return layers;\n};\n\n\n/**\n * Get the pixel for a coordinate. This takes a coordinate in the map view\n * projection and returns the corresponding pixel.\n * @param {module:ol/coordinate~Coordinate} coordinate A map coordinate.\n * @return {module:ol~Pixel} A pixel position in the map viewport.\n * @api\n */\nPluggableMap.prototype.getPixelFromCoordinate = function(coordinate) {\n const frameState = this.frameState_;\n if (!frameState) {\n return null;\n } else {\n return applyTransform(frameState.coordinateToPixelTransform, coordinate.slice(0, 2));\n }\n};\n\n\n/**\n * Get the map renderer.\n * @return {module:ol/renderer/Map} Renderer\n */\nPluggableMap.prototype.getRenderer = function() {\n return this.renderer_;\n};\n\n\n/**\n * Get the size of this map.\n * @return {module:ol/size~Size|undefined} The size in pixels of the map in the DOM.\n * @observable\n * @api\n */\nPluggableMap.prototype.getSize = function() {\n return (\n /** @type {module:ol/size~Size|undefined} */ (this.get(MapProperty.SIZE))\n );\n};\n\n\n/**\n * Get the view associated with this map. A view manages properties such as\n * center and resolution.\n * @return {module:ol/View} The view that controls this map.\n * @observable\n * @api\n */\nPluggableMap.prototype.getView = function() {\n return (\n /** @type {module:ol/View} */ (this.get(MapProperty.VIEW))\n );\n};\n\n\n/**\n * Get the element that serves as the map viewport.\n * @return {Element} Viewport.\n * @api\n */\nPluggableMap.prototype.getViewport = function() {\n return this.viewport_;\n};\n\n\n/**\n * Get the element that serves as the container for overlays. Elements added to\n * this container will let mousedown and touchstart events through to the map,\n * so clicks and gestures on an overlay will trigger {@link module:ol/MapBrowserEvent~MapBrowserEvent}\n * events.\n * @return {!Element} The map's overlay container.\n */\nPluggableMap.prototype.getOverlayContainer = function() {\n return this.overlayContainer_;\n};\n\n\n/**\n * Get the element that serves as a container for overlays that don't allow\n * event propagation. Elements added to this container won't let mousedown and\n * touchstart events through to the map, so clicks and gestures on an overlay\n * don't trigger any {@link module:ol/MapBrowserEvent~MapBrowserEvent}.\n * @return {!Element} The map's overlay container that stops events.\n */\nPluggableMap.prototype.getOverlayContainerStopEvent = function() {\n return this.overlayContainerStopEvent_;\n};\n\n\n/**\n * @param {module:ol/Tile} tile Tile.\n * @param {string} tileSourceKey Tile source key.\n * @param {module:ol/coordinate~Coordinate} tileCenter Tile center.\n * @param {number} tileResolution Tile resolution.\n * @return {number} Tile priority.\n */\nPluggableMap.prototype.getTilePriority = function(tile, tileSourceKey, tileCenter, tileResolution) {\n // Filter out tiles at higher zoom levels than the current zoom level, or that\n // are outside the visible extent.\n const frameState = this.frameState_;\n if (!frameState || !(tileSourceKey in frameState.wantedTiles)) {\n return DROP;\n }\n if (!frameState.wantedTiles[tileSourceKey][tile.getKey()]) {\n return DROP;\n }\n // Prioritize the highest zoom level tiles closest to the focus.\n // Tiles at higher zoom levels are prioritized using Math.log(tileResolution).\n // Within a zoom level, tiles are prioritized by the distance in pixels\n // between the center of the tile and the focus. The factor of 65536 means\n // that the prioritization should behave as desired for tiles up to\n // 65536 * Math.log(2) = 45426 pixels from the focus.\n const deltaX = tileCenter[0] - frameState.focus[0];\n const deltaY = tileCenter[1] - frameState.focus[1];\n return 65536 * Math.log(tileResolution) +\n Math.sqrt(deltaX * deltaX + deltaY * deltaY) / tileResolution;\n};\n\n\n/**\n * @param {Event} browserEvent Browser event.\n * @param {string=} opt_type Type.\n */\nPluggableMap.prototype.handleBrowserEvent = function(browserEvent, opt_type) {\n const type = opt_type || browserEvent.type;\n const mapBrowserEvent = new MapBrowserEvent(type, this, browserEvent);\n this.handleMapBrowserEvent(mapBrowserEvent);\n};\n\n\n/**\n * @param {module:ol/MapBrowserEvent} mapBrowserEvent The event to handle.\n */\nPluggableMap.prototype.handleMapBrowserEvent = function(mapBrowserEvent) {\n if (!this.frameState_) {\n // With no view defined, we cannot translate pixels into geographical\n // coordinates so interactions cannot be used.\n return;\n }\n this.focus_ = mapBrowserEvent.coordinate;\n mapBrowserEvent.frameState = this.frameState_;\n const interactionsArray = this.getInteractions().getArray();\n if (this.dispatchEvent(mapBrowserEvent) !== false) {\n for (let i = interactionsArray.length - 1; i >= 0; i--) {\n const interaction = interactionsArray[i];\n if (!interaction.getActive()) {\n continue;\n }\n const cont = interaction.handleEvent(mapBrowserEvent);\n if (!cont) {\n break;\n }\n }\n }\n};\n\n\n/**\n * @protected\n */\nPluggableMap.prototype.handlePostRender = function() {\n\n const frameState = this.frameState_;\n\n // Manage the tile queue\n // Image loads are expensive and a limited resource, so try to use them\n // efficiently:\n // * When the view is static we allow a large number of parallel tile loads\n // to complete the frame as quickly as possible.\n // * When animating or interacting, image loads can cause janks, so we reduce\n // the maximum number of loads per frame and limit the number of parallel\n // tile loads to remain reactive to view changes and to reduce the chance of\n // loading tiles that will quickly disappear from view.\n const tileQueue = this.tileQueue_;\n if (!tileQueue.isEmpty()) {\n let maxTotalLoading = this.maxTilesLoading_;\n let maxNewLoads = maxTotalLoading;\n if (frameState) {\n const hints = frameState.viewHints;\n if (hints[ViewHint.ANIMATING]) {\n maxTotalLoading = this.loadTilesWhileAnimating_ ? 8 : 0;\n maxNewLoads = 2;\n }\n if (hints[ViewHint.INTERACTING]) {\n maxTotalLoading = this.loadTilesWhileInteracting_ ? 8 : 0;\n maxNewLoads = 2;\n }\n }\n if (tileQueue.getTilesLoading() < maxTotalLoading) {\n tileQueue.reprioritize(); // FIXME only call if view has changed\n tileQueue.loadMoreTiles(maxTotalLoading, maxNewLoads);\n }\n }\n\n const postRenderFunctions = this.postRenderFunctions_;\n for (let i = 0, ii = postRenderFunctions.length; i < ii; ++i) {\n postRenderFunctions[i](this, frameState);\n }\n postRenderFunctions.length = 0;\n};\n\n\n/**\n * @private\n */\nPluggableMap.prototype.handleSizeChanged_ = function() {\n this.render();\n};\n\n\n/**\n * @private\n */\nPluggableMap.prototype.handleTargetChanged_ = function() {\n // target may be undefined, null, a string or an Element.\n // If it's a string we convert it to an Element before proceeding.\n // If it's not now an Element we remove the viewport from the DOM.\n // If it's an Element we append the viewport element to it.\n\n let targetElement;\n if (this.getTarget()) {\n targetElement = this.getTargetElement();\n }\n\n if (this.keyHandlerKeys_) {\n for (let i = 0, ii = this.keyHandlerKeys_.length; i < ii; ++i) {\n unlistenByKey(this.keyHandlerKeys_[i]);\n }\n this.keyHandlerKeys_ = null;\n }\n\n if (!targetElement) {\n this.renderer_.removeLayerRenderers();\n removeNode(this.viewport_);\n if (this.handleResize_ !== undefined) {\n removeEventListener(EventType.RESIZE, this.handleResize_, false);\n this.handleResize_ = undefined;\n }\n } else {\n targetElement.appendChild(this.viewport_);\n\n const keyboardEventTarget = !this.keyboardEventTarget_ ?\n targetElement : this.keyboardEventTarget_;\n this.keyHandlerKeys_ = [\n listen(keyboardEventTarget, EventType.KEYDOWN, this.handleBrowserEvent, this),\n listen(keyboardEventTarget, EventType.KEYPRESS, this.handleBrowserEvent, this)\n ];\n\n if (!this.handleResize_) {\n this.handleResize_ = this.updateSize.bind(this);\n addEventListener(EventType.RESIZE, this.handleResize_, false);\n }\n }\n\n this.updateSize();\n // updateSize calls setSize, so no need to call this.render\n // ourselves here.\n};\n\n\n/**\n * @private\n */\nPluggableMap.prototype.handleTileChange_ = function() {\n this.render();\n};\n\n\n/**\n * @private\n */\nPluggableMap.prototype.handleViewPropertyChanged_ = function() {\n this.render();\n};\n\n\n/**\n * @private\n */\nPluggableMap.prototype.handleViewChanged_ = function() {\n if (this.viewPropertyListenerKey_) {\n unlistenByKey(this.viewPropertyListenerKey_);\n this.viewPropertyListenerKey_ = null;\n }\n if (this.viewChangeListenerKey_) {\n unlistenByKey(this.viewChangeListenerKey_);\n this.viewChangeListenerKey_ = null;\n }\n const view = this.getView();\n if (view) {\n this.viewport_.setAttribute('data-view', getUid(view));\n this.viewPropertyListenerKey_ = listen(\n view, ObjectEventType.PROPERTYCHANGE,\n this.handleViewPropertyChanged_, this);\n this.viewChangeListenerKey_ = listen(\n view, EventType.CHANGE,\n this.handleViewPropertyChanged_, this);\n }\n this.render();\n};\n\n\n/**\n * @private\n */\nPluggableMap.prototype.handleLayerGroupChanged_ = function() {\n if (this.layerGroupPropertyListenerKeys_) {\n this.layerGroupPropertyListenerKeys_.forEach(unlistenByKey);\n this.layerGroupPropertyListenerKeys_ = null;\n }\n const layerGroup = this.getLayerGroup();\n if (layerGroup) {\n this.layerGroupPropertyListenerKeys_ = [\n listen(\n layerGroup, ObjectEventType.PROPERTYCHANGE,\n this.render, this),\n listen(\n layerGroup, EventType.CHANGE,\n this.render, this)\n ];\n }\n this.render();\n};\n\n\n/**\n * @return {boolean} Is rendered.\n */\nPluggableMap.prototype.isRendered = function() {\n return !!this.frameState_;\n};\n\n\n/**\n * Requests an immediate render in a synchronous manner.\n * @api\n */\nPluggableMap.prototype.renderSync = function() {\n if (this.animationDelayKey_) {\n cancelAnimationFrame(this.animationDelayKey_);\n }\n this.animationDelay_();\n};\n\n\n/**\n * Request a map rendering (at the next animation frame).\n * @api\n */\nPluggableMap.prototype.render = function() {\n if (this.animationDelayKey_ === undefined) {\n this.animationDelayKey_ = requestAnimationFrame(this.animationDelay_);\n }\n};\n\n\n/**\n * Remove the given control from the map.\n * @param {module:ol/control/Control} control Control.\n * @return {module:ol/control/Control|undefined} The removed control (or undefined\n * if the control was not found).\n * @api\n */\nPluggableMap.prototype.removeControl = function(control) {\n return this.getControls().remove(control);\n};\n\n\n/**\n * Remove the given interaction from the map.\n * @param {module:ol/interaction/Interaction} interaction Interaction to remove.\n * @return {module:ol/interaction/Interaction|undefined} The removed interaction (or\n * undefined if the interaction was not found).\n * @api\n */\nPluggableMap.prototype.removeInteraction = function(interaction) {\n return this.getInteractions().remove(interaction);\n};\n\n\n/**\n * Removes the given layer from the map.\n * @param {module:ol/layer/Base} layer Layer.\n * @return {module:ol/layer/Base|undefined} The removed layer (or undefined if the\n * layer was not found).\n * @api\n */\nPluggableMap.prototype.removeLayer = function(layer) {\n const layers = this.getLayerGroup().getLayers();\n return layers.remove(layer);\n};\n\n\n/**\n * Remove the given overlay from the map.\n * @param {module:ol/Overlay} overlay Overlay.\n * @return {module:ol/Overlay|undefined} The removed overlay (or undefined\n * if the overlay was not found).\n * @api\n */\nPluggableMap.prototype.removeOverlay = function(overlay) {\n return this.getOverlays().remove(overlay);\n};\n\n\n/**\n * @param {number} time Time.\n * @private\n */\nPluggableMap.prototype.renderFrame_ = function(time) {\n let viewState;\n\n const size = this.getSize();\n const view = this.getView();\n const extent = createEmpty();\n const previousFrameState = this.frameState_;\n /** @type {?module:ol/PluggableMap~FrameState} */\n let frameState = null;\n if (size !== undefined && hasArea(size) && view && view.isDef()) {\n const viewHints = view.getHints(this.frameState_ ? this.frameState_.viewHints : undefined);\n const layerStatesArray = this.getLayerGroup().getLayerStatesArray();\n const layerStates = {};\n for (let i = 0, ii = layerStatesArray.length; i < ii; ++i) {\n layerStates[getUid(layerStatesArray[i].layer)] = layerStatesArray[i];\n }\n viewState = view.getState();\n let focus = this.focus_;\n if (!focus) {\n focus = viewState.center;\n const pixelResolution = viewState.resolution / this.pixelRatio_;\n focus[0] = Math.round(focus[0] / pixelResolution) * pixelResolution;\n focus[1] = Math.round(focus[1] / pixelResolution) * pixelResolution;\n }\n frameState = /** @type {module:ol/PluggableMap~FrameState} */ ({\n animate: false,\n coordinateToPixelTransform: this.coordinateToPixelTransform_,\n extent: extent,\n focus: focus,\n index: this.frameIndex_++,\n layerStates: layerStates,\n layerStatesArray: layerStatesArray,\n pixelRatio: this.pixelRatio_,\n pixelToCoordinateTransform: this.pixelToCoordinateTransform_,\n postRenderFunctions: [],\n size: size,\n skippedFeatureUids: this.skippedFeatureUids_,\n tileQueue: this.tileQueue_,\n time: time,\n usedTiles: {},\n viewState: viewState,\n viewHints: viewHints,\n wantedTiles: {}\n });\n }\n\n if (frameState) {\n frameState.extent = getForViewAndSize(viewState.center,\n viewState.resolution, viewState.rotation, frameState.size, extent);\n }\n\n this.frameState_ = frameState;\n this.renderer_.renderFrame(frameState);\n\n if (frameState) {\n if (frameState.animate) {\n this.render();\n }\n Array.prototype.push.apply(this.postRenderFunctions_, frameState.postRenderFunctions);\n\n if (previousFrameState) {\n const moveStart = !this.previousExtent_ ||\n (!isEmpty(this.previousExtent_) &&\n !equals(frameState.extent, this.previousExtent_));\n if (moveStart) {\n this.dispatchEvent(\n new MapEvent(MapEventType.MOVESTART, this, previousFrameState));\n this.previousExtent_ = createOrUpdateEmpty(this.previousExtent_);\n }\n }\n\n const idle = this.previousExtent_ &&\n !frameState.viewHints[ViewHint.ANIMATING] &&\n !frameState.viewHints[ViewHint.INTERACTING] &&\n !equals(frameState.extent, this.previousExtent_);\n\n if (idle) {\n this.dispatchEvent(new MapEvent(MapEventType.MOVEEND, this, frameState));\n clone(frameState.extent, this.previousExtent_);\n }\n }\n\n this.dispatchEvent(new MapEvent(MapEventType.POSTRENDER, this, frameState));\n\n setTimeout(this.handlePostRender.bind(this), 0);\n\n};\n\n\n/**\n * Sets the layergroup of this map.\n * @param {module:ol/layer/Group} layerGroup A layer group containing the layers in this map.\n * @observable\n * @api\n */\nPluggableMap.prototype.setLayerGroup = function(layerGroup) {\n this.set(MapProperty.LAYERGROUP, layerGroup);\n};\n\n\n/**\n * Set the size of this map.\n * @param {module:ol/size~Size|undefined} size The size in pixels of the map in the DOM.\n * @observable\n * @api\n */\nPluggableMap.prototype.setSize = function(size) {\n this.set(MapProperty.SIZE, size);\n};\n\n\n/**\n * Set the target element to render this map into.\n * @param {Element|string|undefined} target The Element or id of the Element\n * that the map is rendered in.\n * @observable\n * @api\n */\nPluggableMap.prototype.setTarget = function(target) {\n this.set(MapProperty.TARGET, target);\n};\n\n\n/**\n * Set the view for this map.\n * @param {module:ol/View} view The view that controls this map.\n * @observable\n * @api\n */\nPluggableMap.prototype.setView = function(view) {\n this.set(MapProperty.VIEW, view);\n};\n\n\n/**\n * @param {module:ol/Feature} feature Feature.\n */\nPluggableMap.prototype.skipFeature = function(feature) {\n const featureUid = getUid(feature).toString();\n this.skippedFeatureUids_[featureUid] = true;\n this.render();\n};\n\n\n/**\n * Force a recalculation of the map viewport size. This should be called when\n * third-party code changes the size of the map viewport.\n * @api\n */\nPluggableMap.prototype.updateSize = function() {\n const targetElement = this.getTargetElement();\n\n if (!targetElement) {\n this.setSize(undefined);\n } else {\n const computedStyle = getComputedStyle(targetElement);\n this.setSize([\n targetElement.offsetWidth -\n parseFloat(computedStyle['borderLeftWidth']) -\n parseFloat(computedStyle['paddingLeft']) -\n parseFloat(computedStyle['paddingRight']) -\n parseFloat(computedStyle['borderRightWidth']),\n targetElement.offsetHeight -\n parseFloat(computedStyle['borderTopWidth']) -\n parseFloat(computedStyle['paddingTop']) -\n parseFloat(computedStyle['paddingBottom']) -\n parseFloat(computedStyle['borderBottomWidth'])\n ]);\n }\n};\n\n\n/**\n * @param {module:ol/Feature} feature Feature.\n */\nPluggableMap.prototype.unskipFeature = function(feature) {\n const featureUid = getUid(feature).toString();\n delete this.skippedFeatureUids_[featureUid];\n this.render();\n};\n\n\n/**\n * @param {MapOptions} options Map options.\n * @return {module:ol/PluggableMap~MapOptionsInternal} Internal map options.\n */\nfunction createOptionsInternal(options) {\n\n /**\n * @type {Element|Document}\n */\n let keyboardEventTarget = null;\n if (options.keyboardEventTarget !== undefined) {\n keyboardEventTarget = typeof options.keyboardEventTarget === 'string' ?\n document.getElementById(options.keyboardEventTarget) :\n options.keyboardEventTarget;\n }\n\n /**\n * @type {Object.}\n */\n const values = {};\n\n const layerGroup = (options.layers instanceof LayerGroup) ?\n options.layers : new LayerGroup({layers: options.layers});\n values[MapProperty.LAYERGROUP] = layerGroup;\n\n values[MapProperty.TARGET] = options.target;\n\n values[MapProperty.VIEW] = options.view !== undefined ?\n options.view : new View();\n\n let controls;\n if (options.controls !== undefined) {\n if (Array.isArray(options.controls)) {\n controls = new Collection(options.controls.slice());\n } else {\n assert(options.controls instanceof Collection,\n 47); // Expected `controls` to be an array or an `module:ol/Collection~Collection`\n controls = options.controls;\n }\n }\n\n let interactions;\n if (options.interactions !== undefined) {\n if (Array.isArray(options.interactions)) {\n interactions = new Collection(options.interactions.slice());\n } else {\n assert(options.interactions instanceof Collection,\n 48); // Expected `interactions` to be an array or an `module:ol/Collection~Collection`\n interactions = options.interactions;\n }\n }\n\n let overlays;\n if (options.overlays !== undefined) {\n if (Array.isArray(options.overlays)) {\n overlays = new Collection(options.overlays.slice());\n } else {\n assert(options.overlays instanceof Collection,\n 49); // Expected `overlays` to be an array or an `module:ol/Collection~Collection`\n overlays = options.overlays;\n }\n } else {\n overlays = new Collection();\n }\n\n return {\n controls: controls,\n interactions: interactions,\n keyboardEventTarget: keyboardEventTarget,\n overlays: overlays,\n values: values\n };\n\n}\nexport default PluggableMap;\n","/**\n * @module ol/control/Control\n */\nimport {inherits} from '../util.js';\nimport {UNDEFINED} from '../functions.js';\nimport MapEventType from '../MapEventType.js';\nimport BaseObject from '../Object.js';\nimport {removeNode} from '../dom.js';\nimport {listen, unlistenByKey} from '../events.js';\n\n\n/**\n * @typedef {Object} Options\n * @property {Element} [element] The element is the control's\n * container element. This only needs to be specified if you're developing\n * a custom control.\n * @property {function(module:ol/MapEvent)} [render] Function called when\n * the control should be re-rendered. This is called in a `requestAnimationFrame`\n * callback.\n * @property {Element|string} [target] Specify a target if you want\n * the control to be rendered outside of the map's viewport.\n */\n\n\n/**\n * @classdesc\n * A control is a visible widget with a DOM element in a fixed position on the\n * screen. They can involve user input (buttons), or be informational only;\n * the position is determined using CSS. By default these are placed in the\n * container with CSS class name `ol-overlaycontainer-stopevent`, but can use\n * any outside DOM element.\n *\n * This is the base class for controls. You can use it for simple custom\n * controls by creating the element with listeners, creating an instance:\n * ```js\n * var myControl = new Control({element: myElement});\n * ```\n * and then adding this to the map.\n *\n * The main advantage of having this as a control rather than a simple separate\n * DOM element is that preventing propagation is handled for you. Controls\n * will also be objects in a {@link module:ol/Collection~Collection}, so you can use their methods.\n *\n * You can also extend this base for your own control class. See\n * examples/custom-controls for an example of how to do this.\n *\n * @constructor\n * @extends {module:ol/Object}\n * @param {module:ol/control/Control~Options} options Control options.\n * @api\n */\nconst Control = function(options) {\n\n BaseObject.call(this);\n\n /**\n * @protected\n * @type {Element}\n */\n this.element = options.element ? options.element : null;\n\n /**\n * @private\n * @type {Element}\n */\n this.target_ = null;\n\n /**\n * @private\n * @type {module:ol/PluggableMap}\n */\n this.map_ = null;\n\n /**\n * @protected\n * @type {!Array.}\n */\n this.listenerKeys = [];\n\n /**\n * @type {function(module:ol/MapEvent)}\n */\n this.render = options.render ? options.render : UNDEFINED;\n\n if (options.target) {\n this.setTarget(options.target);\n }\n\n};\n\ninherits(Control, BaseObject);\n\n\n/**\n * @inheritDoc\n */\nControl.prototype.disposeInternal = function() {\n removeNode(this.element);\n BaseObject.prototype.disposeInternal.call(this);\n};\n\n\n/**\n * Get the map associated with this control.\n * @return {module:ol/PluggableMap} Map.\n * @api\n */\nControl.prototype.getMap = function() {\n return this.map_;\n};\n\n\n/**\n * Remove the control from its current map and attach it to the new map.\n * Subclasses may set up event handlers to get notified about changes to\n * the map here.\n * @param {module:ol/PluggableMap} map Map.\n * @api\n */\nControl.prototype.setMap = function(map) {\n if (this.map_) {\n removeNode(this.element);\n }\n for (let i = 0, ii = this.listenerKeys.length; i < ii; ++i) {\n unlistenByKey(this.listenerKeys[i]);\n }\n this.listenerKeys.length = 0;\n this.map_ = map;\n if (this.map_) {\n const target = this.target_ ?\n this.target_ : map.getOverlayContainerStopEvent();\n target.appendChild(this.element);\n if (this.render !== UNDEFINED) {\n this.listenerKeys.push(listen(map,\n MapEventType.POSTRENDER, this.render, this));\n }\n map.render();\n }\n};\n\n\n/**\n * This function is used to set a target element for the control. It has no\n * effect if it is called after the control has been added to the map (i.e.\n * after `setMap` is called on the control). If no `target` is set in the\n * options passed to the control constructor and if `setTarget` is not called\n * then the control is added to the map's overlay container.\n * @param {Element|string} target Target.\n * @api\n */\nControl.prototype.setTarget = function(target) {\n this.target_ = typeof target === 'string' ?\n document.getElementById(target) :\n target;\n};\nexport default Control;\n","/**\n * @module ol/layer/Layer\n */\nimport {listen, unlistenByKey} from '../events.js';\nimport EventType from '../events/EventType.js';\nimport {getUid, inherits} from '../util.js';\nimport {getChangeEventType} from '../Object.js';\nimport BaseLayer from '../layer/Base.js';\nimport LayerProperty from '../layer/Property.js';\nimport {assign} from '../obj.js';\nimport RenderEventType from '../render/EventType.js';\nimport SourceState from '../source/State.js';\n\n\n/**\n * @typedef {Object} Options\n * @property {number} [opacity=1] Opacity (0, 1).\n * @property {boolean} [visible=true] Visibility.\n * @property {module:ol/extent~Extent} [extent] The bounding extent for layer rendering. The layer will not be\n * rendered outside of this extent.\n * @property {number} [zIndex=0] The z-index for layer rendering. At rendering time, the layers\n * will be ordered, first by Z-index and then by position.\n * @property {number} [minResolution] The minimum resolution (inclusive) at which this layer will be\n * visible.\n * @property {number} [maxResolution] The maximum resolution (exclusive) below which this layer will\n * be visible.\n * @property {module:ol/source/Source} [source] Source for this layer. If not provided to the constructor,\n * the source can be set by calling {@link module:ol/layer/Layer#setSource layer.setSource(source)} after\n * construction.\n */\n\n\n/**\n * @typedef {Object} State\n * @property {module:ol/layer/Layer} layer\n * @property {number} opacity\n * @property {module:ol/source/Source~State} sourceState\n * @property {boolean} visible\n * @property {boolean} managed\n * @property {module:ol/extent~Extent} [extent]\n * @property {number} zIndex\n * @property {number} maxResolution\n * @property {number} minResolution\n */\n\n\n/**\n * @classdesc\n * Abstract base class; normally only used for creating subclasses and not\n * instantiated in apps.\n * A visual representation of raster or vector map data.\n * Layers group together those properties that pertain to how the data is to be\n * displayed, irrespective of the source of that data.\n *\n * Layers are usually added to a map with {@link module:ol/Map#addLayer}. Components\n * like {@link module:ol/interaction/Select~Select} use unmanaged layers\n * internally. These unmanaged layers are associated with the map using\n * {@link module:ol/layer/Layer~Layer#setMap} instead.\n *\n * A generic `change` event is fired when the state of the source changes.\n *\n * @constructor\n * @abstract\n * @extends {module:ol/layer/Base}\n * @fires module:ol/render/Event~RenderEvent\n * @param {module:ol/layer/Layer~Options} options Layer options.\n * @api\n */\nconst Layer = function(options) {\n\n const baseOptions = assign({}, options);\n delete baseOptions.source;\n\n BaseLayer.call(this, /** @type {module:ol/layer/Base~Options} */ (baseOptions));\n\n /**\n * @private\n * @type {?module:ol/events~EventsKey}\n */\n this.mapPrecomposeKey_ = null;\n\n /**\n * @private\n * @type {?module:ol/events~EventsKey}\n */\n this.mapRenderKey_ = null;\n\n /**\n * @private\n * @type {?module:ol/events~EventsKey}\n */\n this.sourceChangeKey_ = null;\n\n if (options.map) {\n this.setMap(options.map);\n }\n\n listen(this,\n getChangeEventType(LayerProperty.SOURCE),\n this.handleSourcePropertyChange_, this);\n\n const source = options.source ? options.source : null;\n this.setSource(source);\n};\n\ninherits(Layer, BaseLayer);\n\n\n/**\n * Return `true` if the layer is visible, and if the passed resolution is\n * between the layer's minResolution and maxResolution. The comparison is\n * inclusive for `minResolution` and exclusive for `maxResolution`.\n * @param {module:ol/layer/Layer~State} layerState Layer state.\n * @param {number} resolution Resolution.\n * @return {boolean} The layer is visible at the given resolution.\n */\nexport function visibleAtResolution(layerState, resolution) {\n return layerState.visible && resolution >= layerState.minResolution &&\n resolution < layerState.maxResolution;\n}\n\n\n/**\n * @inheritDoc\n */\nLayer.prototype.getLayersArray = function(opt_array) {\n const array = opt_array ? opt_array : [];\n array.push(this);\n return array;\n};\n\n\n/**\n * @inheritDoc\n */\nLayer.prototype.getLayerStatesArray = function(opt_states) {\n const states = opt_states ? opt_states : [];\n states.push(this.getLayerState());\n return states;\n};\n\n\n/**\n * Get the layer source.\n * @return {module:ol/source/Source} The layer source (or `null` if not yet set).\n * @observable\n * @api\n */\nLayer.prototype.getSource = function() {\n const source = this.get(LayerProperty.SOURCE);\n return (\n /** @type {module:ol/source/Source} */ (source) || null\n );\n};\n\n\n/**\n * @inheritDoc\n */\nLayer.prototype.getSourceState = function() {\n const source = this.getSource();\n return !source ? SourceState.UNDEFINED : source.getState();\n};\n\n\n/**\n * @private\n */\nLayer.prototype.handleSourceChange_ = function() {\n this.changed();\n};\n\n\n/**\n * @private\n */\nLayer.prototype.handleSourcePropertyChange_ = function() {\n if (this.sourceChangeKey_) {\n unlistenByKey(this.sourceChangeKey_);\n this.sourceChangeKey_ = null;\n }\n const source = this.getSource();\n if (source) {\n this.sourceChangeKey_ = listen(source,\n EventType.CHANGE, this.handleSourceChange_, this);\n }\n this.changed();\n};\n\n\n/**\n * Sets the layer to be rendered on top of other layers on a map. The map will\n * not manage this layer in its layers collection, and the callback in\n * {@link module:ol/Map#forEachLayerAtPixel} will receive `null` as layer. This\n * is useful for temporary layers. To remove an unmanaged layer from the map,\n * use `#setMap(null)`.\n *\n * To add the layer to a map and have it managed by the map, use\n * {@link module:ol/Map#addLayer} instead.\n * @param {module:ol/PluggableMap} map Map.\n * @api\n */\nLayer.prototype.setMap = function(map) {\n if (this.mapPrecomposeKey_) {\n unlistenByKey(this.mapPrecomposeKey_);\n this.mapPrecomposeKey_ = null;\n }\n if (!map) {\n this.changed();\n }\n if (this.mapRenderKey_) {\n unlistenByKey(this.mapRenderKey_);\n this.mapRenderKey_ = null;\n }\n if (map) {\n this.mapPrecomposeKey_ = listen(map, RenderEventType.PRECOMPOSE, function(evt) {\n const layerState = this.getLayerState();\n layerState.managed = false;\n layerState.zIndex = Infinity;\n evt.frameState.layerStatesArray.push(layerState);\n evt.frameState.layerStates[getUid(this)] = layerState;\n }, this);\n this.mapRenderKey_ = listen(this, EventType.CHANGE, map.render, map);\n this.changed();\n }\n};\n\n\n/**\n * Set the layer source.\n * @param {module:ol/source/Source} source The layer source.\n * @observable\n * @api\n */\nLayer.prototype.setSource = function(source) {\n this.set(LayerProperty.SOURCE, source);\n};\nexport default Layer;\n","/**\n * @module ol/control/Attribution\n */\nimport {inherits} from '../util.js';\nimport {equals} from '../array.js';\nimport Control from '../control/Control.js';\nimport {CLASS_CONTROL, CLASS_UNSELECTABLE, CLASS_COLLAPSED} from '../css.js';\nimport {removeChildren, replaceNode} from '../dom.js';\nimport {listen} from '../events.js';\nimport EventType from '../events/EventType.js';\nimport {visibleAtResolution} from '../layer/Layer.js';\n\n\n/**\n * @typedef {Object} Options\n * @property {string} [className='ol-attribution'] CSS class name.\n * @property {Element|string} [target] Specify a target if you\n * want the control to be rendered outside of the map's\n * viewport.\n * @property {boolean} [collapsible=true] Specify if attributions can\n * be collapsed. If you use an OSM source, should be set to `false` — see\n * {@link https://www.openstreetmap.org/copyright OSM Copyright} —\n * @property {boolean} [collapsed=true] Specify if attributions should\n * be collapsed at startup.\n * @property {string} [tipLabel='Attributions'] Text label to use for the button tip.\n * @property {string} [label='i'] Text label to use for the\n * collapsed attributions button.\n * Instead of text, also an element (e.g. a `span` element) can be used.\n * @property {string|Element} [collapseLabel='»'] Text label to use\n * for the expanded attributions button.\n * Instead of text, also an element (e.g. a `span` element) can be used.\n * @property {function(module:ol/MapEvent)} [render] Function called when\n * the control should be re-rendered. This is called in a `requestAnimationFrame`\n * callback.\n */\n\n\n/**\n * @classdesc\n * Control to show all the attributions associated with the layer sources\n * in the map. This control is one of the default controls included in maps.\n * By default it will show in the bottom right portion of the map, but this can\n * be changed by using a css selector for `.ol-attribution`.\n *\n * @constructor\n * @extends {module:ol/control/Control}\n * @param {module:ol/control/Attribution~Options=} opt_options Attribution options.\n * @api\n */\nconst Attribution = function(opt_options) {\n\n const options = opt_options ? opt_options : {};\n\n /**\n * @private\n * @type {Element}\n */\n this.ulElement_ = document.createElement('UL');\n\n /**\n * @private\n * @type {boolean}\n */\n this.collapsed_ = options.collapsed !== undefined ? options.collapsed : true;\n\n /**\n * @private\n * @type {boolean}\n */\n this.collapsible_ = options.collapsible !== undefined ?\n options.collapsible : true;\n\n if (!this.collapsible_) {\n this.collapsed_ = false;\n }\n\n const className = options.className !== undefined ? options.className : 'ol-attribution';\n\n const tipLabel = options.tipLabel !== undefined ? options.tipLabel : 'Attributions';\n\n const collapseLabel = options.collapseLabel !== undefined ? options.collapseLabel : '\\u00BB';\n\n if (typeof collapseLabel === 'string') {\n /**\n * @private\n * @type {Element}\n */\n this.collapseLabel_ = document.createElement('span');\n this.collapseLabel_.textContent = collapseLabel;\n } else {\n this.collapseLabel_ = collapseLabel;\n }\n\n const label = options.label !== undefined ? options.label : 'i';\n\n if (typeof label === 'string') {\n /**\n * @private\n * @type {Element}\n */\n this.label_ = document.createElement('span');\n this.label_.textContent = label;\n } else {\n this.label_ = label;\n }\n\n\n const activeLabel = (this.collapsible_ && !this.collapsed_) ?\n this.collapseLabel_ : this.label_;\n const button = document.createElement('button');\n button.setAttribute('type', 'button');\n button.title = tipLabel;\n button.appendChild(activeLabel);\n\n listen(button, EventType.CLICK, this.handleClick_, this);\n\n const cssClasses = className + ' ' + CLASS_UNSELECTABLE + ' ' + CLASS_CONTROL +\n (this.collapsed_ && this.collapsible_ ? ' ' + CLASS_COLLAPSED : '') +\n (this.collapsible_ ? '' : ' ol-uncollapsible');\n const element = document.createElement('div');\n element.className = cssClasses;\n element.appendChild(this.ulElement_);\n element.appendChild(button);\n\n Control.call(this, {\n element: element,\n render: options.render || render,\n target: options.target\n });\n\n /**\n * A list of currently rendered resolutions.\n * @type {Array.}\n * @private\n */\n this.renderedAttributions_ = [];\n\n /**\n * @private\n * @type {boolean}\n */\n this.renderedVisible_ = true;\n\n};\n\ninherits(Attribution, Control);\n\n\n/**\n * Get a list of visible attributions.\n * @param {module:ol/PluggableMap~FrameState} frameState Frame state.\n * @return {Array.} Attributions.\n * @private\n */\nAttribution.prototype.getSourceAttributions_ = function(frameState) {\n /**\n * Used to determine if an attribution already exists.\n * @type {!Object.}\n */\n const lookup = {};\n\n /**\n * A list of visible attributions.\n * @type {Array.}\n */\n const visibleAttributions = [];\n\n const layerStatesArray = frameState.layerStatesArray;\n const resolution = frameState.viewState.resolution;\n for (let i = 0, ii = layerStatesArray.length; i < ii; ++i) {\n const layerState = layerStatesArray[i];\n if (!visibleAtResolution(layerState, resolution)) {\n continue;\n }\n\n const source = layerState.layer.getSource();\n if (!source) {\n continue;\n }\n\n const attributionGetter = source.getAttributions();\n if (!attributionGetter) {\n continue;\n }\n\n const attributions = attributionGetter(frameState);\n if (!attributions) {\n continue;\n }\n\n if (Array.isArray(attributions)) {\n for (let j = 0, jj = attributions.length; j < jj; ++j) {\n if (!(attributions[j] in lookup)) {\n visibleAttributions.push(attributions[j]);\n lookup[attributions[j]] = true;\n }\n }\n } else {\n if (!(attributions in lookup)) {\n visibleAttributions.push(attributions);\n lookup[attributions] = true;\n }\n }\n }\n return visibleAttributions;\n};\n\n\n/**\n * Update the attribution element.\n * @param {module:ol/MapEvent} mapEvent Map event.\n * @this {module:ol/control/Attribution}\n * @api\n */\nexport function render(mapEvent) {\n this.updateElement_(mapEvent.frameState);\n}\n\n\n/**\n * @private\n * @param {?module:ol/PluggableMap~FrameState} frameState Frame state.\n */\nAttribution.prototype.updateElement_ = function(frameState) {\n if (!frameState) {\n if (this.renderedVisible_) {\n this.element.style.display = 'none';\n this.renderedVisible_ = false;\n }\n return;\n }\n\n const attributions = this.getSourceAttributions_(frameState);\n\n const visible = attributions.length > 0;\n if (this.renderedVisible_ != visible) {\n this.element.style.display = visible ? '' : 'none';\n this.renderedVisible_ = visible;\n }\n\n if (equals(attributions, this.renderedAttributions_)) {\n return;\n }\n\n removeChildren(this.ulElement_);\n\n // append the attributions\n for (let i = 0, ii = attributions.length; i < ii; ++i) {\n const element = document.createElement('LI');\n element.innerHTML = attributions[i];\n this.ulElement_.appendChild(element);\n }\n\n this.renderedAttributions_ = attributions;\n};\n\n\n/**\n * @param {Event} event The event to handle\n * @private\n */\nAttribution.prototype.handleClick_ = function(event) {\n event.preventDefault();\n this.handleToggle_();\n};\n\n\n/**\n * @private\n */\nAttribution.prototype.handleToggle_ = function() {\n this.element.classList.toggle(CLASS_COLLAPSED);\n if (this.collapsed_) {\n replaceNode(this.collapseLabel_, this.label_);\n } else {\n replaceNode(this.label_, this.collapseLabel_);\n }\n this.collapsed_ = !this.collapsed_;\n};\n\n\n/**\n * Return `true` if the attribution is collapsible, `false` otherwise.\n * @return {boolean} True if the widget is collapsible.\n * @api\n */\nAttribution.prototype.getCollapsible = function() {\n return this.collapsible_;\n};\n\n\n/**\n * Set whether the attribution should be collapsible.\n * @param {boolean} collapsible True if the widget is collapsible.\n * @api\n */\nAttribution.prototype.setCollapsible = function(collapsible) {\n if (this.collapsible_ === collapsible) {\n return;\n }\n this.collapsible_ = collapsible;\n this.element.classList.toggle('ol-uncollapsible');\n if (!collapsible && this.collapsed_) {\n this.handleToggle_();\n }\n};\n\n\n/**\n * Collapse or expand the attribution according to the passed parameter. Will\n * not do anything if the attribution isn't collapsible or if the current\n * collapsed state is already the one requested.\n * @param {boolean} collapsed True if the widget is collapsed.\n * @api\n */\nAttribution.prototype.setCollapsed = function(collapsed) {\n if (!this.collapsible_ || this.collapsed_ === collapsed) {\n return;\n }\n this.handleToggle_();\n};\n\n\n/**\n * Return `true` when the attribution is currently collapsed or `false`\n * otherwise.\n * @return {boolean} True if the widget is collapsed.\n * @api\n */\nAttribution.prototype.getCollapsed = function() {\n return this.collapsed_;\n};\nexport default Attribution;\n","/**\n * @module ol/control/Rotate\n */\n\nimport Control from '../control/Control.js';\nimport {CLASS_CONTROL, CLASS_HIDDEN, CLASS_UNSELECTABLE} from '../css.js';\nimport {easeOut} from '../easing.js';\nimport {listen} from '../events.js';\nimport EventType from '../events/EventType.js';\nimport {inherits} from '../util.js';\n\n\n/**\n * @typedef {Object} Options\n * @property {string} [className='ol-rotate'] CSS class name.\n * @property {string|Element} [label='⇧'] Text label to use for the rotate button.\n * Instead of text, also an element (e.g. a `span` element) can be used.\n * @property {string} [tipLabel='Reset rotation'] Text label to use for the rotate tip.\n * @property {number} [duration=250] Animation duration in milliseconds.\n * @property {boolean} [autoHide=true] Hide the control when rotation is 0.\n * @property {function(module:ol/MapEvent)} [render] Function called when the control should\n * be re-rendered. This is called in a `requestAnimationFrame` callback.\n * @property {function()} [resetNorth] Function called when the control is clicked.\n * This will override the default `resetNorth`.\n * @property {Element|string} [target] Specify a target if you want the control to be\n * rendered outside of the map's viewport.\n */\n\n\n/**\n * @classdesc\n * A button control to reset rotation to 0.\n * To style this control use css selector `.ol-rotate`. A `.ol-hidden` css\n * selector is added to the button when the rotation is 0.\n *\n * @constructor\n * @extends {module:ol/control/Control}\n * @param {module:ol/control/Rotate~Options=} opt_options Rotate options.\n * @api\n */\nconst Rotate = function(opt_options) {\n\n const options = opt_options ? opt_options : {};\n\n const className = options.className !== undefined ? options.className : 'ol-rotate';\n\n const label = options.label !== undefined ? options.label : '\\u21E7';\n\n /**\n * @type {Element}\n * @private\n */\n this.label_ = null;\n\n if (typeof label === 'string') {\n this.label_ = document.createElement('span');\n this.label_.className = 'ol-compass';\n this.label_.textContent = label;\n } else {\n this.label_ = label;\n this.label_.classList.add('ol-compass');\n }\n\n const tipLabel = options.tipLabel ? options.tipLabel : 'Reset rotation';\n\n const button = document.createElement('button');\n button.className = className + '-reset';\n button.setAttribute('type', 'button');\n button.title = tipLabel;\n button.appendChild(this.label_);\n\n listen(button, EventType.CLICK,\n Rotate.prototype.handleClick_, this);\n\n const cssClasses = className + ' ' + CLASS_UNSELECTABLE + ' ' + CLASS_CONTROL;\n const element = document.createElement('div');\n element.className = cssClasses;\n element.appendChild(button);\n\n this.callResetNorth_ = options.resetNorth ? options.resetNorth : undefined;\n\n Control.call(this, {\n element: element,\n render: options.render || render,\n target: options.target\n });\n\n /**\n * @type {number}\n * @private\n */\n this.duration_ = options.duration !== undefined ? options.duration : 250;\n\n /**\n * @type {boolean}\n * @private\n */\n this.autoHide_ = options.autoHide !== undefined ? options.autoHide : true;\n\n /**\n * @private\n * @type {number|undefined}\n */\n this.rotation_ = undefined;\n\n if (this.autoHide_) {\n this.element.classList.add(CLASS_HIDDEN);\n }\n\n};\n\ninherits(Rotate, Control);\n\n\n/**\n * @param {Event} event The event to handle\n * @private\n */\nRotate.prototype.handleClick_ = function(event) {\n event.preventDefault();\n if (this.callResetNorth_ !== undefined) {\n this.callResetNorth_();\n } else {\n this.resetNorth_();\n }\n};\n\n\n/**\n * @private\n */\nRotate.prototype.resetNorth_ = function() {\n const map = this.getMap();\n const view = map.getView();\n if (!view) {\n // the map does not have a view, so we can't act\n // upon it\n return;\n }\n if (view.getRotation() !== undefined) {\n if (this.duration_ > 0) {\n view.animate({\n rotation: 0,\n duration: this.duration_,\n easing: easeOut\n });\n } else {\n view.setRotation(0);\n }\n }\n};\n\n\n/**\n * Update the rotate control element.\n * @param {module:ol/MapEvent} mapEvent Map event.\n * @this {module:ol/control/Rotate}\n * @api\n */\nexport function render(mapEvent) {\n const frameState = mapEvent.frameState;\n if (!frameState) {\n return;\n }\n const rotation = frameState.viewState.rotation;\n if (rotation != this.rotation_) {\n const transform = 'rotate(' + rotation + 'rad)';\n if (this.autoHide_) {\n const contains = this.element.classList.contains(CLASS_HIDDEN);\n if (!contains && rotation === 0) {\n this.element.classList.add(CLASS_HIDDEN);\n } else if (contains && rotation !== 0) {\n this.element.classList.remove(CLASS_HIDDEN);\n }\n }\n this.label_.style.msTransform = transform;\n this.label_.style.webkitTransform = transform;\n this.label_.style.transform = transform;\n }\n this.rotation_ = rotation;\n}\n\nexport default Rotate;\n","/**\n * @module ol/control/Zoom\n */\nimport {inherits} from '../util.js';\nimport {listen} from '../events.js';\nimport EventType from '../events/EventType.js';\nimport Control from '../control/Control.js';\nimport {CLASS_CONTROL, CLASS_UNSELECTABLE} from '../css.js';\nimport {easeOut} from '../easing.js';\n\n\n/**\n * @typedef {Object} Options\n * @property {number} [duration=250] Animation duration in milliseconds.\n * @property {string} [className='ol-zoom'] CSS class name.\n * @property {string|Element} [zoomInLabel='+'] Text label to use for the zoom-in\n * button. Instead of text, also an element (e.g. a `span` element) can be used.\n * @property {string|Element} [zoomOutLabel='-'] Text label to use for the zoom-out button.\n * Instead of text, also an element (e.g. a `span` element) can be used.\n * @property {string} [zoomInTipLabel='Zoom in'] Text label to use for the button tip.\n * @property {string} [zoomOutTipLabel='Zoom out'] Text label to use for the button tip.\n * @property {number} [delta=1] The zoom delta applied on each click.\n * @property {Element|string} [target] Specify a target if you want the control to be\n * rendered outside of the map's viewport.\n */\n\n\n/**\n * @classdesc\n * A control with 2 buttons, one for zoom in and one for zoom out.\n * This control is one of the default controls of a map. To style this control\n * use css selectors `.ol-zoom-in` and `.ol-zoom-out`.\n *\n * @constructor\n * @extends {module:ol/control/Control}\n * @param {module:ol/control/Zoom~Options=} opt_options Zoom options.\n * @api\n */\nconst Zoom = function(opt_options) {\n\n const options = opt_options ? opt_options : {};\n\n const className = options.className !== undefined ? options.className : 'ol-zoom';\n\n const delta = options.delta !== undefined ? options.delta : 1;\n\n const zoomInLabel = options.zoomInLabel !== undefined ? options.zoomInLabel : '+';\n const zoomOutLabel = options.zoomOutLabel !== undefined ? options.zoomOutLabel : '\\u2212';\n\n const zoomInTipLabel = options.zoomInTipLabel !== undefined ?\n options.zoomInTipLabel : 'Zoom in';\n const zoomOutTipLabel = options.zoomOutTipLabel !== undefined ?\n options.zoomOutTipLabel : 'Zoom out';\n\n const inElement = document.createElement('button');\n inElement.className = className + '-in';\n inElement.setAttribute('type', 'button');\n inElement.title = zoomInTipLabel;\n inElement.appendChild(\n typeof zoomInLabel === 'string' ? document.createTextNode(zoomInLabel) : zoomInLabel\n );\n\n listen(inElement, EventType.CLICK,\n Zoom.prototype.handleClick_.bind(this, delta));\n\n const outElement = document.createElement('button');\n outElement.className = className + '-out';\n outElement.setAttribute('type', 'button');\n outElement.title = zoomOutTipLabel;\n outElement.appendChild(\n typeof zoomOutLabel === 'string' ? document.createTextNode(zoomOutLabel) : zoomOutLabel\n );\n\n listen(outElement, EventType.CLICK,\n Zoom.prototype.handleClick_.bind(this, -delta));\n\n const cssClasses = className + ' ' + CLASS_UNSELECTABLE + ' ' + CLASS_CONTROL;\n const element = document.createElement('div');\n element.className = cssClasses;\n element.appendChild(inElement);\n element.appendChild(outElement);\n\n Control.call(this, {\n element: element,\n target: options.target\n });\n\n /**\n * @type {number}\n * @private\n */\n this.duration_ = options.duration !== undefined ? options.duration : 250;\n\n};\n\ninherits(Zoom, Control);\n\n\n/**\n * @param {number} delta Zoom delta.\n * @param {Event} event The event to handle\n * @private\n */\nZoom.prototype.handleClick_ = function(delta, event) {\n event.preventDefault();\n this.zoomByDelta_(delta);\n};\n\n\n/**\n * @param {number} delta Zoom delta.\n * @private\n */\nZoom.prototype.zoomByDelta_ = function(delta) {\n const map = this.getMap();\n const view = map.getView();\n if (!view) {\n // the map does not have a view, so we can't act\n // upon it\n return;\n }\n const currentResolution = view.getResolution();\n if (currentResolution) {\n const newResolution = view.constrainResolution(currentResolution, delta);\n if (this.duration_ > 0) {\n if (view.getAnimating()) {\n view.cancelAnimations();\n }\n view.animate({\n resolution: newResolution,\n duration: this.duration_,\n easing: easeOut\n });\n } else {\n view.setResolution(newResolution);\n }\n }\n};\nexport default Zoom;\n","/**\n * @module ol/control/util\n */\nimport Collection from '../Collection.js';\nimport Attribution from './Attribution.js';\nimport Rotate from './Rotate.js';\nimport Zoom from './Zoom.js';\n\n\n/**\n * @typedef {Object} DefaultsOptions\n * @property {boolean} [attribution=true] Include\n * {@link module:ol/control/Attribution~Attribution}.\n * @property {module:ol/control/Attribution~Options} [attributionOptions]\n * Options for {@link module:ol/control/Attribution~Attribution}.\n * @property {boolean} [rotate=true] Include\n * {@link module:ol/control/Rotate~Rotate}.\n * @property {module:ol/control/Rotate~Options} [rotateOptions] Options\n * for {@link module:ol/control/Rotate~Rotate}.\n * @property {boolean} [zoom] Include {@link module:ol/control/Zoom~Zoom}.\n * @property {module:ol/control/Zoom~Options} [zoomOptions] Options for\n * {@link module:ol/control/Zoom~Zoom}.\n * @api\n */\n\n\n/**\n * Set of controls included in maps by default. Unless configured otherwise,\n * this returns a collection containing an instance of each of the following\n * controls:\n * * {@link module:ol/control/Zoom~Zoom}\n * * {@link module:ol/control/Rotate~Rotate}\n * * {@link module:ol/control/Attribution~Attribution}\n *\n * @param {module:ol/control/util~DefaultsOptions=} opt_options\n * Defaults options.\n * @return {module:ol/Collection.}\n * Controls.\n * @function module:ol/control.defaults\n * @api\n */\nexport function defaults(opt_options) {\n\n const options = opt_options ? opt_options : {};\n\n const controls = new Collection();\n\n const zoomControl = options.zoom !== undefined ? options.zoom : true;\n if (zoomControl) {\n controls.push(new Zoom(options.zoomOptions));\n }\n\n const rotateControl = options.rotate !== undefined ? options.rotate : true;\n if (rotateControl) {\n controls.push(new Rotate(options.rotateOptions));\n }\n\n const attributionControl = options.attribution !== undefined ?\n options.attribution : true;\n if (attributionControl) {\n controls.push(new Attribution(options.attributionOptions));\n }\n\n return controls;\n}\n","/**\n * @module ol/interaction/Property\n */\n\n/**\n * @enum {string}\n */\nexport default {\n ACTIVE: 'active'\n};\n","/**\n * @module ol/interaction/Interaction\n */\nimport {inherits} from '../util.js';\nimport BaseObject from '../Object.js';\nimport {easeOut, linear} from '../easing.js';\nimport InteractionProperty from '../interaction/Property.js';\nimport {clamp} from '../math.js';\n\n\n/**\n * Object literal with config options for interactions.\n * @typedef {Object} InteractionOptions\n * @property {function(module:ol/MapBrowserEvent):boolean} handleEvent\n * Method called by the map to notify the interaction that a browser event was\n * dispatched to the map. If the function returns a falsy value, propagation of\n * the event to other interactions in the map's interactions chain will be\n * prevented (this includes functions with no explicit return).\n */\n\n\n/**\n * @classdesc\n * Abstract base class; normally only used for creating subclasses and not\n * instantiated in apps.\n * User actions that change the state of the map. Some are similar to controls,\n * but are not associated with a DOM element.\n * For example, {@link module:ol/interaction/KeyboardZoom~KeyboardZoom} is\n * functionally the same as {@link module:ol/control/Zoom~Zoom}, but triggered\n * by a keyboard event not a button element event.\n * Although interactions do not have a DOM element, some of them do render\n * vectors and so are visible on the screen.\n *\n * @constructor\n * @param {module:ol/interaction/Interaction~InteractionOptions} options Options.\n * @extends {module:ol/Object}\n * @api\n */\nconst Interaction = function(options) {\n\n BaseObject.call(this);\n\n /**\n * @private\n * @type {module:ol/PluggableMap}\n */\n this.map_ = null;\n\n this.setActive(true);\n\n /**\n * @type {function(module:ol/MapBrowserEvent):boolean}\n */\n this.handleEvent = options.handleEvent;\n\n};\n\ninherits(Interaction, BaseObject);\n\n\n/**\n * Return whether the interaction is currently active.\n * @return {boolean} `true` if the interaction is active, `false` otherwise.\n * @observable\n * @api\n */\nInteraction.prototype.getActive = function() {\n return /** @type {boolean} */ (this.get(InteractionProperty.ACTIVE));\n};\n\n\n/**\n * Get the map associated with this interaction.\n * @return {module:ol/PluggableMap} Map.\n * @api\n */\nInteraction.prototype.getMap = function() {\n return this.map_;\n};\n\n\n/**\n * Activate or deactivate the interaction.\n * @param {boolean} active Active.\n * @observable\n * @api\n */\nInteraction.prototype.setActive = function(active) {\n this.set(InteractionProperty.ACTIVE, active);\n};\n\n\n/**\n * Remove the interaction from its current map and attach it to the new map.\n * Subclasses may set up event handlers to get notified about changes to\n * the map here.\n * @param {module:ol/PluggableMap} map Map.\n */\nInteraction.prototype.setMap = function(map) {\n this.map_ = map;\n};\n\n\n/**\n * @param {module:ol/View} view View.\n * @param {module:ol/coordinate~Coordinate} delta Delta.\n * @param {number=} opt_duration Duration.\n */\nexport function pan(view, delta, opt_duration) {\n const currentCenter = view.getCenter();\n if (currentCenter) {\n const center = view.constrainCenter(\n [currentCenter[0] + delta[0], currentCenter[1] + delta[1]]);\n if (opt_duration) {\n view.animate({\n duration: opt_duration,\n easing: linear,\n center: center\n });\n } else {\n view.setCenter(center);\n }\n }\n}\n\n\n/**\n * @param {module:ol/View} view View.\n * @param {number|undefined} rotation Rotation.\n * @param {module:ol/coordinate~Coordinate=} opt_anchor Anchor coordinate.\n * @param {number=} opt_duration Duration.\n */\nexport function rotate(view, rotation, opt_anchor, opt_duration) {\n rotation = view.constrainRotation(rotation, 0);\n rotateWithoutConstraints(view, rotation, opt_anchor, opt_duration);\n}\n\n\n/**\n * @param {module:ol/View} view View.\n * @param {number|undefined} rotation Rotation.\n * @param {module:ol/coordinate~Coordinate=} opt_anchor Anchor coordinate.\n * @param {number=} opt_duration Duration.\n */\nexport function rotateWithoutConstraints(view, rotation, opt_anchor, opt_duration) {\n if (rotation !== undefined) {\n const currentRotation = view.getRotation();\n const currentCenter = view.getCenter();\n if (currentRotation !== undefined && currentCenter && opt_duration > 0) {\n view.animate({\n rotation: rotation,\n anchor: opt_anchor,\n duration: opt_duration,\n easing: easeOut\n });\n } else {\n view.rotate(rotation, opt_anchor);\n }\n }\n}\n\n\n/**\n * @param {module:ol/View} view View.\n * @param {number|undefined} resolution Resolution to go to.\n * @param {module:ol/coordinate~Coordinate=} opt_anchor Anchor coordinate.\n * @param {number=} opt_duration Duration.\n * @param {number=} opt_direction Zooming direction; > 0 indicates\n * zooming out, in which case the constraints system will select\n * the largest nearest resolution; < 0 indicates zooming in, in\n * which case the constraints system will select the smallest\n * nearest resolution; == 0 indicates that the zooming direction\n * is unknown/not relevant, in which case the constraints system\n * will select the nearest resolution. If not defined 0 is\n * assumed.\n */\nexport function zoom(view, resolution, opt_anchor, opt_duration, opt_direction) {\n resolution = view.constrainResolution(resolution, 0, opt_direction);\n zoomWithoutConstraints(view, resolution, opt_anchor, opt_duration);\n}\n\n\n/**\n * @param {module:ol/View} view View.\n * @param {number} delta Delta from previous zoom level.\n * @param {module:ol/coordinate~Coordinate=} opt_anchor Anchor coordinate.\n * @param {number=} opt_duration Duration.\n */\nexport function zoomByDelta(view, delta, opt_anchor, opt_duration) {\n const currentResolution = view.getResolution();\n let resolution = view.constrainResolution(currentResolution, delta, 0);\n\n if (resolution !== undefined) {\n const resolutions = view.getResolutions();\n resolution = clamp(\n resolution,\n view.getMinResolution() || resolutions[resolutions.length - 1],\n view.getMaxResolution() || resolutions[0]);\n }\n\n // If we have a constraint on center, we need to change the anchor so that the\n // new center is within the extent. We first calculate the new center, apply\n // the constraint to it, and then calculate back the anchor\n if (opt_anchor && resolution !== undefined && resolution !== currentResolution) {\n const currentCenter = view.getCenter();\n let center = view.calculateCenterZoom(resolution, opt_anchor);\n center = view.constrainCenter(center);\n\n opt_anchor = [\n (resolution * currentCenter[0] - currentResolution * center[0]) /\n (resolution - currentResolution),\n (resolution * currentCenter[1] - currentResolution * center[1]) /\n (resolution - currentResolution)\n ];\n }\n\n zoomWithoutConstraints(view, resolution, opt_anchor, opt_duration);\n}\n\n\n/**\n * @param {module:ol/View} view View.\n * @param {number|undefined} resolution Resolution to go to.\n * @param {module:ol/coordinate~Coordinate=} opt_anchor Anchor coordinate.\n * @param {number=} opt_duration Duration.\n */\nexport function zoomWithoutConstraints(view, resolution, opt_anchor, opt_duration) {\n if (resolution) {\n const currentResolution = view.getResolution();\n const currentCenter = view.getCenter();\n if (currentResolution !== undefined && currentCenter &&\n resolution !== currentResolution && opt_duration) {\n view.animate({\n resolution: resolution,\n anchor: opt_anchor,\n duration: opt_duration,\n easing: easeOut\n });\n } else {\n if (opt_anchor) {\n const center = view.calculateCenterZoom(resolution, opt_anchor);\n view.setCenter(center);\n }\n view.setResolution(resolution);\n }\n }\n}\n\nexport default Interaction;\n","/**\n * @module ol/interaction/DoubleClickZoom\n */\nimport {inherits} from '../util.js';\nimport MapBrowserEventType from '../MapBrowserEventType.js';\nimport Interaction, {zoomByDelta} from '../interaction/Interaction.js';\n\n\n/**\n * @typedef {Object} Options\n * @property {number} [duration=250] Animation duration in milliseconds.\n * @property {number} [delta=1] The zoom delta applied on each double click.\n */\n\n\n/**\n * @classdesc\n * Allows the user to zoom by double-clicking on the map.\n *\n * @constructor\n * @extends {module:ol/interaction/Interaction}\n * @param {module:ol/interaction/DoubleClickZoom~Options=} opt_options Options.\n * @api\n */\nconst DoubleClickZoom = function(opt_options) {\n\n const options = opt_options ? opt_options : {};\n\n /**\n * @private\n * @type {number}\n */\n this.delta_ = options.delta ? options.delta : 1;\n\n Interaction.call(this, {\n handleEvent: handleEvent\n });\n\n /**\n * @private\n * @type {number}\n */\n this.duration_ = options.duration !== undefined ? options.duration : 250;\n\n};\n\ninherits(DoubleClickZoom, Interaction);\n\n\n/**\n * Handles the {@link module:ol/MapBrowserEvent map browser event} (if it was a\n * doubleclick) and eventually zooms the map.\n * @param {module:ol/MapBrowserEvent} mapBrowserEvent Map browser event.\n * @return {boolean} `false` to stop event propagation.\n * @this {module:ol/interaction/DoubleClickZoom}\n */\nfunction handleEvent(mapBrowserEvent) {\n let stopEvent = false;\n const browserEvent = mapBrowserEvent.originalEvent;\n if (mapBrowserEvent.type == MapBrowserEventType.DBLCLICK) {\n const map = mapBrowserEvent.map;\n const anchor = mapBrowserEvent.coordinate;\n const delta = browserEvent.shiftKey ? -this.delta_ : this.delta_;\n const view = map.getView();\n zoomByDelta(view, delta, anchor, this.duration_);\n mapBrowserEvent.preventDefault();\n stopEvent = true;\n }\n return !stopEvent;\n}\n\nexport default DoubleClickZoom;\n","/**\n * @module ol/events/condition\n */\nimport MapBrowserEventType from '../MapBrowserEventType.js';\nimport {assert} from '../asserts.js';\nimport {TRUE, FALSE} from '../functions.js';\nimport {WEBKIT, MAC} from '../has.js';\n\n\n/**\n * A function that takes an {@link module:ol/MapBrowserEvent} and returns a\n * `{boolean}`. If the condition is met, true should be returned.\n *\n * @typedef {function(this: ?, module:ol/MapBrowserEvent): boolean} Condition\n */\n\n\n/**\n * Return `true` if only the alt-key is pressed, `false` otherwise (e.g. when\n * additionally the shift-key is pressed).\n *\n * @param {module:ol/MapBrowserEvent} mapBrowserEvent Map browser event.\n * @return {boolean} True if only the alt key is pressed.\n * @api\n */\nexport const altKeyOnly = function(mapBrowserEvent) {\n const originalEvent = mapBrowserEvent.originalEvent;\n return (\n originalEvent.altKey &&\n !(originalEvent.metaKey || originalEvent.ctrlKey) &&\n !originalEvent.shiftKey);\n};\n\n\n/**\n * Return `true` if only the alt-key and shift-key is pressed, `false` otherwise\n * (e.g. when additionally the platform-modifier-key is pressed).\n *\n * @param {module:ol/MapBrowserEvent} mapBrowserEvent Map browser event.\n * @return {boolean} True if only the alt and shift keys are pressed.\n * @api\n */\nexport const altShiftKeysOnly = function(mapBrowserEvent) {\n const originalEvent = mapBrowserEvent.originalEvent;\n return (\n originalEvent.altKey &&\n !(originalEvent.metaKey || originalEvent.ctrlKey) &&\n originalEvent.shiftKey);\n};\n\n\n/**\n * Return `true` if the map has the focus. This condition requires a map target\n * element with a `tabindex` attribute, e.g. `
`.\n *\n * @param {module:ol/MapBrowserEvent} event Map browser event.\n * @return {boolean} The map has the focus.\n * @api\n */\nexport const focus = function(event) {\n return event.target.getTargetElement() === document.activeElement;\n};\n\n\n/**\n * Return always true.\n *\n * @param {module:ol/MapBrowserEvent} mapBrowserEvent Map browser event.\n * @return {boolean} True.\n * @function\n * @api\n */\nexport const always = TRUE;\n\n\n/**\n * Return `true` if the event is a `click` event, `false` otherwise.\n *\n * @param {module:ol/MapBrowserEvent} mapBrowserEvent Map browser event.\n * @return {boolean} True if the event is a map `click` event.\n * @api\n */\nexport const click = function(mapBrowserEvent) {\n return mapBrowserEvent.type == MapBrowserEventType.CLICK;\n};\n\n\n/**\n * Return `true` if the event has an \"action\"-producing mouse button.\n *\n * By definition, this includes left-click on windows/linux, and left-click\n * without the ctrl key on Macs.\n *\n * @param {module:ol/MapBrowserEvent} mapBrowserEvent Map browser event.\n * @return {boolean} The result.\n */\nexport const mouseActionButton = function(mapBrowserEvent) {\n const originalEvent = mapBrowserEvent.originalEvent;\n return originalEvent.button == 0 &&\n !(WEBKIT && MAC && originalEvent.ctrlKey);\n};\n\n\n/**\n * Return always false.\n *\n * @param {module:ol/MapBrowserEvent} mapBrowserEvent Map browser event.\n * @return {boolean} False.\n * @function\n * @api\n */\nexport const never = FALSE;\n\n\n/**\n * Return `true` if the browser event is a `pointermove` event, `false`\n * otherwise.\n *\n * @param {module:ol/MapBrowserEvent} mapBrowserEvent Map browser event.\n * @return {boolean} True if the browser event is a `pointermove` event.\n * @api\n */\nexport const pointerMove = function(mapBrowserEvent) {\n return mapBrowserEvent.type == 'pointermove';\n};\n\n\n/**\n * Return `true` if the event is a map `singleclick` event, `false` otherwise.\n *\n * @param {module:ol/MapBrowserEvent} mapBrowserEvent Map browser event.\n * @return {boolean} True if the event is a map `singleclick` event.\n * @api\n */\nexport const singleClick = function(mapBrowserEvent) {\n return mapBrowserEvent.type == MapBrowserEventType.SINGLECLICK;\n};\n\n\n/**\n * Return `true` if the event is a map `dblclick` event, `false` otherwise.\n *\n * @param {module:ol/MapBrowserEvent} mapBrowserEvent Map browser event.\n * @return {boolean} True if the event is a map `dblclick` event.\n * @api\n */\nexport const doubleClick = function(mapBrowserEvent) {\n return mapBrowserEvent.type == MapBrowserEventType.DBLCLICK;\n};\n\n\n/**\n * Return `true` if no modifier key (alt-, shift- or platform-modifier-key) is\n * pressed.\n *\n * @param {module:ol/MapBrowserEvent} mapBrowserEvent Map browser event.\n * @return {boolean} True only if there no modifier keys are pressed.\n * @api\n */\nexport const noModifierKeys = function(mapBrowserEvent) {\n const originalEvent = mapBrowserEvent.originalEvent;\n return (\n !originalEvent.altKey &&\n !(originalEvent.metaKey || originalEvent.ctrlKey) &&\n !originalEvent.shiftKey);\n};\n\n\n/**\n * Return `true` if only the platform-modifier-key (the meta-key on Mac,\n * ctrl-key otherwise) is pressed, `false` otherwise (e.g. when additionally\n * the shift-key is pressed).\n *\n * @param {module:ol/MapBrowserEvent} mapBrowserEvent Map browser event.\n * @return {boolean} True if only the platform modifier key is pressed.\n * @api\n */\nexport const platformModifierKeyOnly = function(mapBrowserEvent) {\n const originalEvent = mapBrowserEvent.originalEvent;\n return !originalEvent.altKey &&\n (MAC ? originalEvent.metaKey : originalEvent.ctrlKey) &&\n !originalEvent.shiftKey;\n};\n\n\n/**\n * Return `true` if only the shift-key is pressed, `false` otherwise (e.g. when\n * additionally the alt-key is pressed).\n *\n * @param {module:ol/MapBrowserEvent} mapBrowserEvent Map browser event.\n * @return {boolean} True if only the shift key is pressed.\n * @api\n */\nexport const shiftKeyOnly = function(mapBrowserEvent) {\n const originalEvent = mapBrowserEvent.originalEvent;\n return (\n !originalEvent.altKey &&\n !(originalEvent.metaKey || originalEvent.ctrlKey) &&\n originalEvent.shiftKey);\n};\n\n\n/**\n * Return `true` if the target element is not editable, i.e. not a ``-,\n * `