2
.gitignore
vendored
2
.gitignore
vendored
@@ -2,5 +2,3 @@
|
||||
/coverage/
|
||||
/dist/
|
||||
node_modules/
|
||||
src/index.js
|
||||
src/ol/package.json
|
||||
|
||||
@@ -7,7 +7,7 @@ import buble from 'rollup-plugin-buble';
|
||||
import sourcemaps from 'rollup-plugin-sourcemaps';
|
||||
|
||||
export default {
|
||||
input: 'src/index.js',
|
||||
input: 'build/index.js',
|
||||
output: [
|
||||
{file: 'build/ol.js', format: 'iife', sourcemap: true}
|
||||
],
|
||||
|
||||
25
package.json
25
package.json
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "openlayers",
|
||||
"name": "ol",
|
||||
"version": "5.0.3",
|
||||
"description": "OpenLayers mapping library",
|
||||
"keywords": [
|
||||
@@ -7,6 +7,7 @@
|
||||
"mapping",
|
||||
"ol"
|
||||
],
|
||||
"private": true,
|
||||
"homepage": "https://openlayers.org/",
|
||||
"scripts": {
|
||||
"lint": "eslint tasks test src/ol examples config",
|
||||
@@ -15,18 +16,13 @@
|
||||
"karma": "karma start test/karma.config.js",
|
||||
"serve-examples": "webpack-dev-server --config examples/webpack/config.js --mode development --watch",
|
||||
"build-examples": "webpack --config examples/webpack/config.js --mode production",
|
||||
"build-index": "node tasks/generate-index",
|
||||
"prepare-package": "node tasks/prepare-package",
|
||||
"prebuild": "npm run prepare-package && npm run build-index",
|
||||
"prepare": "npm run prepare-package",
|
||||
"build": "rollup --config config/rollup.js && cleancss --source-map src/ol/ol.css -o build/ol.css",
|
||||
"presrc-closure": "npm run prebuild",
|
||||
"src-closure": "node tasks/transform-types",
|
||||
"pretypecheck": "npm run src-closure",
|
||||
"typecheck": "node tasks/typecheck",
|
||||
"build-package": "npm run transpile && node tasks/prepare-package",
|
||||
"build-index": "npm run build-package && node tasks/generate-index",
|
||||
"build-legacy": "rm -rf build && npm run build-index && rollup --config config/rollup.js && cleancss --source-map src/ol/ol.css -o build/ol.css",
|
||||
"transpile": "rm -rf build/ol && mkdir -p build && buble --input src/ol --output build/ol --no modules --sourcemap",
|
||||
"apidoc": "jsdoc config/jsdoc/api/index.md -c config/jsdoc/api/conf.json -P package.json -d build/apidoc"
|
||||
},
|
||||
"main": "src/ol/index.js",
|
||||
"main": "index.js",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git://github.com/openlayers/openlayers.git"
|
||||
@@ -41,20 +37,18 @@
|
||||
"rbush": "2.0.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"babel-core": "^6.26.3",
|
||||
"babel-plugin-jsdoc-closure": "1.5.1",
|
||||
"buble": "^0.19.3",
|
||||
"buble-loader": "^0.5.1",
|
||||
"chaikin-smooth": "^1.0.4",
|
||||
"clean-css-cli": "4.1.11",
|
||||
"copy-webpack-plugin": "^4.4.1",
|
||||
"coveralls": "3.0.1",
|
||||
"eslint": "5.0.1",
|
||||
"eslint-config-openlayers": "^9.2.0",
|
||||
"eslint-config-openlayers": "^10.0.0",
|
||||
"expect.js": "0.3.1",
|
||||
"front-matter": "^2.1.2",
|
||||
"fs-extra": "^6.0.0",
|
||||
"glob": "^7.1.2",
|
||||
"google-closure-compiler": "20180610.0.2",
|
||||
"handlebars": "4.0.11",
|
||||
"istanbul": "0.4.5",
|
||||
"jquery": "3.3.1",
|
||||
@@ -72,7 +66,6 @@
|
||||
"mustache": "^2.3.0",
|
||||
"pixelmatch": "^4.0.2",
|
||||
"proj4": "2.4.4",
|
||||
"recast": "0.15.2",
|
||||
"rollup": "0.62.0",
|
||||
"rollup-plugin-buble": "0.19.2",
|
||||
"rollup-plugin-commonjs": "9.1.3",
|
||||
|
||||
@@ -1,40 +1,44 @@
|
||||
/**
|
||||
* @module ol/AssertionError
|
||||
*/
|
||||
import {VERSION, inherits} from './util.js';
|
||||
import {VERSION} from './util.js';
|
||||
|
||||
/**
|
||||
* Error object thrown when an assertion failed. This is an ECMA-262 Error,
|
||||
* extended with a `code` property.
|
||||
* @see {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error}
|
||||
* @constructor
|
||||
* @extends {Error}
|
||||
* @param {number} code Error code.
|
||||
*/
|
||||
const AssertionError = function(code) {
|
||||
|
||||
const path = VERSION.split('-')[0];
|
||||
class AssertionError extends Error {
|
||||
|
||||
/**
|
||||
* @type {string}
|
||||
* @param {number} code Error code.
|
||||
*/
|
||||
this.message = 'Assertion failed. See https://openlayers.org/en/' + path +
|
||||
'/doc/errors/#' + code + ' for details.';
|
||||
constructor(code) {
|
||||
const path = VERSION.split('-')[0];
|
||||
const message = 'Assertion failed. See https://openlayers.org/en/' + path +
|
||||
'/doc/errors/#' + code + ' for details.';
|
||||
|
||||
/**
|
||||
* Error code. The meaning of the code can be found on
|
||||
* {@link https://openlayers.org/en/latest/doc/errors/} (replace `latest` with
|
||||
* the version found in the OpenLayers script's header comment if a version
|
||||
* other than the latest is used).
|
||||
* @type {number}
|
||||
* @api
|
||||
*/
|
||||
this.code = code;
|
||||
super(message);
|
||||
|
||||
this.name = 'AssertionError';
|
||||
/**
|
||||
* Error code. The meaning of the code can be found on
|
||||
* {@link https://openlayers.org/en/latest/doc/errors/} (replace `latest` with
|
||||
* the version found in the OpenLayers script's header comment if a version
|
||||
* other than the latest is used).
|
||||
* @type {number}
|
||||
* @api
|
||||
*/
|
||||
this.code = code;
|
||||
|
||||
};
|
||||
/**
|
||||
* @type {string}
|
||||
*/
|
||||
this.name = 'AssertionError';
|
||||
|
||||
inherits(AssertionError, Error);
|
||||
// Re-assign message, see https://github.com/Rich-Harris/buble/issues/40
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default AssertionError;
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
/**
|
||||
* @module ol/Collection
|
||||
*/
|
||||
import {inherits} from './util.js';
|
||||
import AssertionError from './AssertionError.js';
|
||||
import CollectionEventType from './CollectionEventType.js';
|
||||
import BaseObject from './Object.js';
|
||||
@@ -21,26 +20,26 @@ const Property = {
|
||||
* @classdesc
|
||||
* Events emitted by {@link module:ol/Collection~Collection} instances are instances of this
|
||||
* type.
|
||||
*
|
||||
* @constructor
|
||||
* @extends {module:ol/events/Event}
|
||||
* @param {module:ol/CollectionEventType} type Type.
|
||||
* @param {*=} opt_element Element.
|
||||
*/
|
||||
export const CollectionEvent = function(type, opt_element) {
|
||||
|
||||
Event.call(this, type);
|
||||
export class CollectionEvent extends Event {
|
||||
|
||||
/**
|
||||
* The element that is added to or removed from the collection.
|
||||
* @type {*}
|
||||
* @api
|
||||
* @param {module:ol/CollectionEventType} type Type.
|
||||
* @param {*=} opt_element Element.
|
||||
*/
|
||||
this.element = opt_element;
|
||||
constructor(type, opt_element) {
|
||||
super(type);
|
||||
|
||||
};
|
||||
/**
|
||||
* The element that is added to or removed from the collection.
|
||||
* @type {*}
|
||||
* @api
|
||||
*/
|
||||
this.element = opt_element;
|
||||
|
||||
inherits(CollectionEvent, Event);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
@@ -57,244 +56,231 @@ inherits(CollectionEvent, Event);
|
||||
* Collection; they trigger events on the appropriate object, not on the
|
||||
* Collection as a whole.
|
||||
*
|
||||
* @constructor
|
||||
* @extends {module:ol/Object}
|
||||
* @fires module:ol/Collection~CollectionEvent
|
||||
* @param {Array.<T>=} opt_array Array.
|
||||
* @param {module:ol/Collection~Options=} opt_options Collection options.
|
||||
* @template T
|
||||
* @api
|
||||
*/
|
||||
const Collection = function(opt_array, opt_options) {
|
||||
|
||||
BaseObject.call(this);
|
||||
|
||||
const options = opt_options || {};
|
||||
class Collection extends BaseObject {
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {boolean}
|
||||
* @param {Array.<T>=} opt_array Array.
|
||||
* @param {module:ol/Collection~Options=} opt_options Collection options.
|
||||
* @template T
|
||||
*/
|
||||
this.unique_ = !!options.unique;
|
||||
constructor(opt_array, opt_options) {
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {!Array.<T>}
|
||||
*/
|
||||
this.array_ = opt_array ? opt_array : [];
|
||||
super();
|
||||
|
||||
if (this.unique_) {
|
||||
for (let i = 0, ii = this.array_.length; i < ii; ++i) {
|
||||
this.assertUnique_(this.array_[i], i);
|
||||
}
|
||||
}
|
||||
const options = opt_options || {};
|
||||
|
||||
this.updateLength_();
|
||||
/**
|
||||
* @private
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.unique_ = !!options.unique;
|
||||
|
||||
};
|
||||
/**
|
||||
* @private
|
||||
* @type {!Array.<T>}
|
||||
*/
|
||||
this.array_ = opt_array ? opt_array : [];
|
||||
|
||||
inherits(Collection, BaseObject);
|
||||
|
||||
|
||||
/**
|
||||
* Remove all elements from the collection.
|
||||
* @api
|
||||
*/
|
||||
Collection.prototype.clear = function() {
|
||||
while (this.getLength() > 0) {
|
||||
this.pop();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Add elements to the collection. This pushes each item in the provided array
|
||||
* to the end of the collection.
|
||||
* @param {!Array.<T>} arr Array.
|
||||
* @return {module:ol/Collection.<T>} This collection.
|
||||
* @api
|
||||
*/
|
||||
Collection.prototype.extend = function(arr) {
|
||||
for (let i = 0, ii = arr.length; i < ii; ++i) {
|
||||
this.push(arr[i]);
|
||||
}
|
||||
return this;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Iterate over each element, calling the provided callback.
|
||||
* @param {function(T, number, Array.<T>): *} f The function to call
|
||||
* for every element. This function takes 3 arguments (the element, the
|
||||
* index and the array). The return value is ignored.
|
||||
* @api
|
||||
*/
|
||||
Collection.prototype.forEach = function(f) {
|
||||
const array = this.array_;
|
||||
for (let i = 0, ii = array.length; i < ii; ++i) {
|
||||
f(array[i], i, array);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get a reference to the underlying Array object. Warning: if the array
|
||||
* is mutated, no events will be dispatched by the collection, and the
|
||||
* collection's "length" property won't be in sync with the actual length
|
||||
* of the array.
|
||||
* @return {!Array.<T>} Array.
|
||||
* @api
|
||||
*/
|
||||
Collection.prototype.getArray = function() {
|
||||
return this.array_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get the element at the provided index.
|
||||
* @param {number} index Index.
|
||||
* @return {T} Element.
|
||||
* @api
|
||||
*/
|
||||
Collection.prototype.item = function(index) {
|
||||
return this.array_[index];
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get the length of this collection.
|
||||
* @return {number} The length of the array.
|
||||
* @observable
|
||||
* @api
|
||||
*/
|
||||
Collection.prototype.getLength = function() {
|
||||
return /** @type {number} */ (this.get(Property.LENGTH));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Insert an element at the provided index.
|
||||
* @param {number} index Index.
|
||||
* @param {T} elem Element.
|
||||
* @api
|
||||
*/
|
||||
Collection.prototype.insertAt = function(index, elem) {
|
||||
if (this.unique_) {
|
||||
this.assertUnique_(elem);
|
||||
}
|
||||
this.array_.splice(index, 0, elem);
|
||||
this.updateLength_();
|
||||
this.dispatchEvent(
|
||||
new CollectionEvent(CollectionEventType.ADD, elem));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Remove the last element of the collection and return it.
|
||||
* Return `undefined` if the collection is empty.
|
||||
* @return {T|undefined} Element.
|
||||
* @api
|
||||
*/
|
||||
Collection.prototype.pop = function() {
|
||||
return this.removeAt(this.getLength() - 1);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Insert the provided element at the end of the collection.
|
||||
* @param {T} elem Element.
|
||||
* @return {number} New length of the collection.
|
||||
* @api
|
||||
*/
|
||||
Collection.prototype.push = function(elem) {
|
||||
if (this.unique_) {
|
||||
this.assertUnique_(elem);
|
||||
}
|
||||
const n = this.getLength();
|
||||
this.insertAt(n, elem);
|
||||
return this.getLength();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Remove the first occurrence of an element from the collection.
|
||||
* @param {T} elem Element.
|
||||
* @return {T|undefined} The removed element or undefined if none found.
|
||||
* @api
|
||||
*/
|
||||
Collection.prototype.remove = function(elem) {
|
||||
const arr = this.array_;
|
||||
for (let i = 0, ii = arr.length; i < ii; ++i) {
|
||||
if (arr[i] === elem) {
|
||||
return this.removeAt(i);
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Remove the element at the provided index and return it.
|
||||
* Return `undefined` if the collection does not contain this index.
|
||||
* @param {number} index Index.
|
||||
* @return {T|undefined} Value.
|
||||
* @api
|
||||
*/
|
||||
Collection.prototype.removeAt = function(index) {
|
||||
const prev = this.array_[index];
|
||||
this.array_.splice(index, 1);
|
||||
this.updateLength_();
|
||||
this.dispatchEvent(new CollectionEvent(CollectionEventType.REMOVE, prev));
|
||||
return prev;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Set the element at the provided index.
|
||||
* @param {number} index Index.
|
||||
* @param {T} elem Element.
|
||||
* @api
|
||||
*/
|
||||
Collection.prototype.setAt = function(index, elem) {
|
||||
const n = this.getLength();
|
||||
if (index < n) {
|
||||
if (this.unique_) {
|
||||
this.assertUnique_(elem, index);
|
||||
for (let i = 0, ii = this.array_.length; i < ii; ++i) {
|
||||
this.assertUnique_(this.array_[i], i);
|
||||
}
|
||||
}
|
||||
const prev = this.array_[index];
|
||||
this.array_[index] = elem;
|
||||
this.dispatchEvent(
|
||||
new CollectionEvent(CollectionEventType.REMOVE, prev));
|
||||
|
||||
this.updateLength_();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all elements from the collection.
|
||||
* @api
|
||||
*/
|
||||
clear() {
|
||||
while (this.getLength() > 0) {
|
||||
this.pop();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add elements to the collection. This pushes each item in the provided array
|
||||
* to the end of the collection.
|
||||
* @param {!Array.<T>} arr Array.
|
||||
* @return {module:ol/Collection.<T>} This collection.
|
||||
* @api
|
||||
*/
|
||||
extend(arr) {
|
||||
for (let i = 0, ii = arr.length; i < ii; ++i) {
|
||||
this.push(arr[i]);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterate over each element, calling the provided callback.
|
||||
* @param {function(T, number, Array.<T>): *} f The function to call
|
||||
* for every element. This function takes 3 arguments (the element, the
|
||||
* index and the array). The return value is ignored.
|
||||
* @api
|
||||
*/
|
||||
forEach(f) {
|
||||
const array = this.array_;
|
||||
for (let i = 0, ii = array.length; i < ii; ++i) {
|
||||
f(array[i], i, array);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a reference to the underlying Array object. Warning: if the array
|
||||
* is mutated, no events will be dispatched by the collection, and the
|
||||
* collection's "length" property won't be in sync with the actual length
|
||||
* of the array.
|
||||
* @return {!Array.<T>} Array.
|
||||
* @api
|
||||
*/
|
||||
getArray() {
|
||||
return this.array_;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the element at the provided index.
|
||||
* @param {number} index Index.
|
||||
* @return {T} Element.
|
||||
* @api
|
||||
*/
|
||||
item(index) {
|
||||
return this.array_[index];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the length of this collection.
|
||||
* @return {number} The length of the array.
|
||||
* @observable
|
||||
* @api
|
||||
*/
|
||||
getLength() {
|
||||
return /** @type {number} */ (this.get(Property.LENGTH));
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert an element at the provided index.
|
||||
* @param {number} index Index.
|
||||
* @param {T} elem Element.
|
||||
* @api
|
||||
*/
|
||||
insertAt(index, elem) {
|
||||
if (this.unique_) {
|
||||
this.assertUnique_(elem);
|
||||
}
|
||||
this.array_.splice(index, 0, elem);
|
||||
this.updateLength_();
|
||||
this.dispatchEvent(
|
||||
new CollectionEvent(CollectionEventType.ADD, elem));
|
||||
} else {
|
||||
for (let j = n; j < index; ++j) {
|
||||
this.insertAt(j, undefined);
|
||||
}
|
||||
this.insertAt(index, elem);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Remove the last element of the collection and return it.
|
||||
* Return `undefined` if the collection is empty.
|
||||
* @return {T|undefined} Element.
|
||||
* @api
|
||||
*/
|
||||
pop() {
|
||||
return this.removeAt(this.getLength() - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
Collection.prototype.updateLength_ = function() {
|
||||
this.set(Property.LENGTH, this.array_.length);
|
||||
};
|
||||
/**
|
||||
* Insert the provided element at the end of the collection.
|
||||
* @param {T} elem Element.
|
||||
* @return {number} New length of the collection.
|
||||
* @api
|
||||
*/
|
||||
push(elem) {
|
||||
if (this.unique_) {
|
||||
this.assertUnique_(elem);
|
||||
}
|
||||
const n = this.getLength();
|
||||
this.insertAt(n, elem);
|
||||
return this.getLength();
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the first occurrence of an element from the collection.
|
||||
* @param {T} elem Element.
|
||||
* @return {T|undefined} The removed element or undefined if none found.
|
||||
* @api
|
||||
*/
|
||||
remove(elem) {
|
||||
const arr = this.array_;
|
||||
for (let i = 0, ii = arr.length; i < ii; ++i) {
|
||||
if (arr[i] === elem) {
|
||||
return this.removeAt(i);
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {T} elem Element.
|
||||
* @param {number=} opt_except Optional index to ignore.
|
||||
*/
|
||||
Collection.prototype.assertUnique_ = function(elem, opt_except) {
|
||||
for (let i = 0, ii = this.array_.length; i < ii; ++i) {
|
||||
if (this.array_[i] === elem && i !== opt_except) {
|
||||
throw new AssertionError(58);
|
||||
/**
|
||||
* Remove the element at the provided index and return it.
|
||||
* Return `undefined` if the collection does not contain this index.
|
||||
* @param {number} index Index.
|
||||
* @return {T|undefined} Value.
|
||||
* @api
|
||||
*/
|
||||
removeAt(index) {
|
||||
const prev = this.array_[index];
|
||||
this.array_.splice(index, 1);
|
||||
this.updateLength_();
|
||||
this.dispatchEvent(new CollectionEvent(CollectionEventType.REMOVE, prev));
|
||||
return prev;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the element at the provided index.
|
||||
* @param {number} index Index.
|
||||
* @param {T} elem Element.
|
||||
* @api
|
||||
*/
|
||||
setAt(index, elem) {
|
||||
const n = this.getLength();
|
||||
if (index < n) {
|
||||
if (this.unique_) {
|
||||
this.assertUnique_(elem, index);
|
||||
}
|
||||
const prev = this.array_[index];
|
||||
this.array_[index] = elem;
|
||||
this.dispatchEvent(
|
||||
new CollectionEvent(CollectionEventType.REMOVE, prev));
|
||||
this.dispatchEvent(
|
||||
new CollectionEvent(CollectionEventType.ADD, elem));
|
||||
} else {
|
||||
for (let j = n; j < index; ++j) {
|
||||
this.insertAt(j, undefined);
|
||||
}
|
||||
this.insertAt(index, elem);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
updateLength_() {
|
||||
this.set(Property.LENGTH, this.array_.length);
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {T} elem Element.
|
||||
* @param {number=} opt_except Optional index to ignore.
|
||||
*/
|
||||
assertUnique_(elem, opt_except) {
|
||||
for (let i = 0, ii = this.array_.length; i < ii; ++i) {
|
||||
if (this.array_[i] === elem && i !== opt_except) {
|
||||
throw new AssertionError(58);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export default Collection;
|
||||
|
||||
@@ -5,9 +5,18 @@ import {UNDEFINED} from './functions.js';
|
||||
|
||||
/**
|
||||
* Objects that need to clean up after themselves.
|
||||
* @constructor
|
||||
*/
|
||||
const Disposable = function() {};
|
||||
class Disposable {
|
||||
/**
|
||||
* Clean up.
|
||||
*/
|
||||
dispose() {
|
||||
if (!this.disposed_) {
|
||||
this.disposed_ = true;
|
||||
this.disposeInternal();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The object has already been disposed.
|
||||
@@ -16,16 +25,6 @@ const Disposable = function() {};
|
||||
*/
|
||||
Disposable.prototype.disposed_ = false;
|
||||
|
||||
/**
|
||||
* Clean up.
|
||||
*/
|
||||
Disposable.prototype.dispose = function() {
|
||||
if (!this.disposed_) {
|
||||
this.disposed_ = true;
|
||||
this.disposeInternal();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Extension point for disposable objects.
|
||||
* @protected
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
import {assert} from './asserts.js';
|
||||
import {listen, unlisten, unlistenByKey} from './events.js';
|
||||
import EventType from './events/EventType.js';
|
||||
import {inherits} from './util.js';
|
||||
import BaseObject, {getChangeEventType} from './Object.js';
|
||||
import Geometry from './geom/Geometry.js';
|
||||
import Style from './style/Style.js';
|
||||
@@ -51,235 +50,224 @@ import Style from './style/Style.js';
|
||||
* var point = feature.getGeometry();
|
||||
* ```
|
||||
*
|
||||
* @constructor
|
||||
* @extends {module:ol/Object}
|
||||
* @param {module:ol/geom/Geometry|Object.<string, *>=} opt_geometryOrProperties
|
||||
* You may pass a Geometry object directly, or an object literal containing
|
||||
* properties. If you pass an object literal, you may include a Geometry
|
||||
* associated with a `geometry` key.
|
||||
* @api
|
||||
*/
|
||||
const Feature = function(opt_geometryOrProperties) {
|
||||
|
||||
BaseObject.call(this);
|
||||
class Feature extends BaseObject {
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {number|string|undefined}
|
||||
* @param {module:ol/geom/Geometry|Object.<string, *>=} opt_geometryOrProperties
|
||||
* You may pass a Geometry object directly, or an object literal containing
|
||||
* properties. If you pass an object literal, you may include a Geometry
|
||||
* associated with a `geometry` key.
|
||||
*/
|
||||
this.id_ = undefined;
|
||||
constructor(opt_geometryOrProperties) {
|
||||
|
||||
/**
|
||||
* @type {string}
|
||||
* @private
|
||||
*/
|
||||
this.geometryName_ = 'geometry';
|
||||
super();
|
||||
|
||||
/**
|
||||
* User provided style.
|
||||
* @private
|
||||
* @type {module:ol/style/Style|Array.<module:ol/style/Style>|module:ol/style/Style~StyleFunction}
|
||||
*/
|
||||
this.style_ = null;
|
||||
/**
|
||||
* @private
|
||||
* @type {number|string|undefined}
|
||||
*/
|
||||
this.id_ = undefined;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {module:ol/style/Style~StyleFunction|undefined}
|
||||
*/
|
||||
this.styleFunction_ = undefined;
|
||||
/**
|
||||
* @type {string}
|
||||
* @private
|
||||
*/
|
||||
this.geometryName_ = 'geometry';
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {?module:ol/events~EventsKey}
|
||||
*/
|
||||
this.geometryChangeKey_ = null;
|
||||
/**
|
||||
* User provided style.
|
||||
* @private
|
||||
* @type {module:ol/style/Style|Array.<module:ol/style/Style>|module:ol/style/Style~StyleFunction}
|
||||
*/
|
||||
this.style_ = null;
|
||||
|
||||
listen(
|
||||
this, getChangeEventType(this.geometryName_),
|
||||
this.handleGeometryChanged_, this);
|
||||
/**
|
||||
* @private
|
||||
* @type {module:ol/style/Style~StyleFunction|undefined}
|
||||
*/
|
||||
this.styleFunction_ = undefined;
|
||||
|
||||
if (opt_geometryOrProperties !== undefined) {
|
||||
if (opt_geometryOrProperties instanceof Geometry ||
|
||||
!opt_geometryOrProperties) {
|
||||
const geometry = opt_geometryOrProperties;
|
||||
this.setGeometry(geometry);
|
||||
} else {
|
||||
/** @type {Object.<string, *>} */
|
||||
const properties = opt_geometryOrProperties;
|
||||
this.setProperties(properties);
|
||||
/**
|
||||
* @private
|
||||
* @type {?module:ol/events~EventsKey}
|
||||
*/
|
||||
this.geometryChangeKey_ = null;
|
||||
|
||||
listen(
|
||||
this, getChangeEventType(this.geometryName_),
|
||||
this.handleGeometryChanged_, this);
|
||||
|
||||
if (opt_geometryOrProperties !== undefined) {
|
||||
if (opt_geometryOrProperties instanceof Geometry ||
|
||||
!opt_geometryOrProperties) {
|
||||
const geometry = opt_geometryOrProperties;
|
||||
this.setGeometry(geometry);
|
||||
} else {
|
||||
/** @type {Object.<string, *>} */
|
||||
const properties = opt_geometryOrProperties;
|
||||
this.setProperties(properties);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
inherits(Feature, BaseObject);
|
||||
|
||||
|
||||
/**
|
||||
* Clone this feature. If the original feature has a geometry it
|
||||
* is also cloned. The feature id is not set in the clone.
|
||||
* @return {module:ol/Feature} The clone.
|
||||
* @api
|
||||
*/
|
||||
Feature.prototype.clone = function() {
|
||||
const clone = new Feature(this.getProperties());
|
||||
clone.setGeometryName(this.getGeometryName());
|
||||
const geometry = this.getGeometry();
|
||||
if (geometry) {
|
||||
clone.setGeometry(geometry.clone());
|
||||
/**
|
||||
* Clone this feature. If the original feature has a geometry it
|
||||
* is also cloned. The feature id is not set in the clone.
|
||||
* @return {module:ol/Feature} The clone.
|
||||
* @api
|
||||
*/
|
||||
clone() {
|
||||
const clone = new Feature(this.getProperties());
|
||||
clone.setGeometryName(this.getGeometryName());
|
||||
const geometry = this.getGeometry();
|
||||
if (geometry) {
|
||||
clone.setGeometry(geometry.clone());
|
||||
}
|
||||
const style = this.getStyle();
|
||||
if (style) {
|
||||
clone.setStyle(style);
|
||||
}
|
||||
return clone;
|
||||
}
|
||||
const style = this.getStyle();
|
||||
if (style) {
|
||||
clone.setStyle(style);
|
||||
|
||||
/**
|
||||
* Get the feature's default geometry. A feature may have any number of named
|
||||
* geometries. The "default" geometry (the one that is rendered by default) is
|
||||
* set when calling {@link module:ol/Feature~Feature#setGeometry}.
|
||||
* @return {module:ol/geom/Geometry|undefined} The default geometry for the feature.
|
||||
* @api
|
||||
* @observable
|
||||
*/
|
||||
getGeometry() {
|
||||
return (
|
||||
/** @type {module:ol/geom/Geometry|undefined} */ (this.get(this.geometryName_))
|
||||
);
|
||||
}
|
||||
return clone;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get the feature's default geometry. A feature may have any number of named
|
||||
* geometries. The "default" geometry (the one that is rendered by default) is
|
||||
* set when calling {@link module:ol/Feature~Feature#setGeometry}.
|
||||
* @return {module:ol/geom/Geometry|undefined} The default geometry for the feature.
|
||||
* @api
|
||||
* @observable
|
||||
*/
|
||||
Feature.prototype.getGeometry = function() {
|
||||
return (
|
||||
/** @type {module:ol/geom/Geometry|undefined} */ (this.get(this.geometryName_))
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get the feature identifier. This is a stable identifier for the feature and
|
||||
* is either set when reading data from a remote source or set explicitly by
|
||||
* calling {@link module:ol/Feature~Feature#setId}.
|
||||
* @return {number|string|undefined} Id.
|
||||
* @api
|
||||
*/
|
||||
Feature.prototype.getId = function() {
|
||||
return this.id_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get the name of the feature's default geometry. By default, the default
|
||||
* geometry is named `geometry`.
|
||||
* @return {string} Get the property name associated with the default geometry
|
||||
* for this feature.
|
||||
* @api
|
||||
*/
|
||||
Feature.prototype.getGeometryName = function() {
|
||||
return this.geometryName_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get the feature's style. Will return what was provided to the
|
||||
* {@link module:ol/Feature~Feature#setStyle} method.
|
||||
* @return {module:ol/style/Style|Array.<module:ol/style/Style>|module:ol/style/Style~StyleFunction} The feature style.
|
||||
* @api
|
||||
*/
|
||||
Feature.prototype.getStyle = function() {
|
||||
return this.style_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get the feature's style function.
|
||||
* @return {module:ol/style/Style~StyleFunction|undefined} Return a function
|
||||
* representing the current style of this feature.
|
||||
* @api
|
||||
*/
|
||||
Feature.prototype.getStyleFunction = function() {
|
||||
return this.styleFunction_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
Feature.prototype.handleGeometryChange_ = function() {
|
||||
this.changed();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
Feature.prototype.handleGeometryChanged_ = function() {
|
||||
if (this.geometryChangeKey_) {
|
||||
unlistenByKey(this.geometryChangeKey_);
|
||||
this.geometryChangeKey_ = null;
|
||||
/**
|
||||
* Get the feature identifier. This is a stable identifier for the feature and
|
||||
* is either set when reading data from a remote source or set explicitly by
|
||||
* calling {@link module:ol/Feature~Feature#setId}.
|
||||
* @return {number|string|undefined} Id.
|
||||
* @api
|
||||
*/
|
||||
getId() {
|
||||
return this.id_;
|
||||
}
|
||||
const geometry = this.getGeometry();
|
||||
if (geometry) {
|
||||
this.geometryChangeKey_ = listen(geometry,
|
||||
EventType.CHANGE, this.handleGeometryChange_, this);
|
||||
|
||||
/**
|
||||
* Get the name of the feature's default geometry. By default, the default
|
||||
* geometry is named `geometry`.
|
||||
* @return {string} Get the property name associated with the default geometry
|
||||
* for this feature.
|
||||
* @api
|
||||
*/
|
||||
getGeometryName() {
|
||||
return this.geometryName_;
|
||||
}
|
||||
this.changed();
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the feature's style. Will return what was provided to the
|
||||
* {@link module:ol/Feature~Feature#setStyle} method.
|
||||
* @return {module:ol/style/Style|Array.<module:ol/style/Style>|module:ol/style/Style~StyleFunction} The feature style.
|
||||
* @api
|
||||
*/
|
||||
getStyle() {
|
||||
return this.style_;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the default geometry for the feature. This will update the property
|
||||
* with the name returned by {@link module:ol/Feature~Feature#getGeometryName}.
|
||||
* @param {module:ol/geom/Geometry|undefined} geometry The new geometry.
|
||||
* @api
|
||||
* @observable
|
||||
*/
|
||||
Feature.prototype.setGeometry = function(geometry) {
|
||||
this.set(this.geometryName_, geometry);
|
||||
};
|
||||
/**
|
||||
* Get the feature's style function.
|
||||
* @return {module:ol/style/Style~StyleFunction|undefined} Return a function
|
||||
* representing the current style of this feature.
|
||||
* @api
|
||||
*/
|
||||
getStyleFunction() {
|
||||
return this.styleFunction_;
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
handleGeometryChange_() {
|
||||
this.changed();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the style for the feature. This can be a single style object, an array
|
||||
* of styles, or a function that takes a resolution and returns an array of
|
||||
* styles. If it is `null` the feature has no style (a `null` style).
|
||||
* @param {module:ol/style/Style|Array.<module:ol/style/Style>|module:ol/style/Style~StyleFunction} style Style for this feature.
|
||||
* @api
|
||||
* @fires module:ol/events/Event~Event#event:change
|
||||
*/
|
||||
Feature.prototype.setStyle = function(style) {
|
||||
this.style_ = style;
|
||||
this.styleFunction_ = !style ? undefined : createStyleFunction(style);
|
||||
this.changed();
|
||||
};
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
handleGeometryChanged_() {
|
||||
if (this.geometryChangeKey_) {
|
||||
unlistenByKey(this.geometryChangeKey_);
|
||||
this.geometryChangeKey_ = null;
|
||||
}
|
||||
const geometry = this.getGeometry();
|
||||
if (geometry) {
|
||||
this.geometryChangeKey_ = listen(geometry,
|
||||
EventType.CHANGE, this.handleGeometryChange_, this);
|
||||
}
|
||||
this.changed();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the default geometry for the feature. This will update the property
|
||||
* with the name returned by {@link module:ol/Feature~Feature#getGeometryName}.
|
||||
* @param {module:ol/geom/Geometry|undefined} geometry The new geometry.
|
||||
* @api
|
||||
* @observable
|
||||
*/
|
||||
setGeometry(geometry) {
|
||||
this.set(this.geometryName_, geometry);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the feature id. The feature id is considered stable and may be used when
|
||||
* requesting features or comparing identifiers returned from a remote source.
|
||||
* The feature id can be used with the
|
||||
* {@link module:ol/source/Vector~VectorSource#getFeatureById} method.
|
||||
* @param {number|string|undefined} id The feature id.
|
||||
* @api
|
||||
* @fires module:ol/events/Event~Event#event:change
|
||||
*/
|
||||
Feature.prototype.setId = function(id) {
|
||||
this.id_ = id;
|
||||
this.changed();
|
||||
};
|
||||
/**
|
||||
* Set the style for the feature. This can be a single style object, an array
|
||||
* of styles, or a function that takes a resolution and returns an array of
|
||||
* styles. If it is `null` the feature has no style (a `null` style).
|
||||
* @param {module:ol/style/Style|Array.<module:ol/style/Style>|module:ol/style/Style~StyleFunction} style Style for this feature.
|
||||
* @api
|
||||
* @fires module:ol/events/Event~Event#event:change
|
||||
*/
|
||||
setStyle(style) {
|
||||
this.style_ = style;
|
||||
this.styleFunction_ = !style ? undefined : createStyleFunction(style);
|
||||
this.changed();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the feature id. The feature id is considered stable and may be used when
|
||||
* requesting features or comparing identifiers returned from a remote source.
|
||||
* The feature id can be used with the
|
||||
* {@link module:ol/source/Vector~VectorSource#getFeatureById} method.
|
||||
* @param {number|string|undefined} id The feature id.
|
||||
* @api
|
||||
* @fires module:ol/events/Event~Event#event:change
|
||||
*/
|
||||
setId(id) {
|
||||
this.id_ = id;
|
||||
this.changed();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the property name to be used when getting the feature's default geometry.
|
||||
* When calling {@link module:ol/Feature~Feature#getGeometry}, the value of the property with
|
||||
* this name will be returned.
|
||||
* @param {string} name The property name of the default geometry.
|
||||
* @api
|
||||
*/
|
||||
Feature.prototype.setGeometryName = function(name) {
|
||||
unlisten(
|
||||
this, getChangeEventType(this.geometryName_),
|
||||
this.handleGeometryChanged_, this);
|
||||
this.geometryName_ = name;
|
||||
listen(
|
||||
this, getChangeEventType(this.geometryName_),
|
||||
this.handleGeometryChanged_, this);
|
||||
this.handleGeometryChanged_();
|
||||
};
|
||||
/**
|
||||
* Set the property name to be used when getting the feature's default geometry.
|
||||
* When calling {@link module:ol/Feature~Feature#getGeometry}, the value of the property with
|
||||
* this name will be returned.
|
||||
* @param {string} name The property name of the default geometry.
|
||||
* @api
|
||||
*/
|
||||
setGeometryName(name) {
|
||||
unlisten(
|
||||
this, getChangeEventType(this.geometryName_),
|
||||
this.handleGeometryChanged_, this);
|
||||
this.geometryName_ = name;
|
||||
listen(
|
||||
this, getChangeEventType(this.geometryName_),
|
||||
this.handleGeometryChanged_, this);
|
||||
this.handleGeometryChanged_();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
/**
|
||||
* @module ol/Geolocation
|
||||
*/
|
||||
import {inherits} from './util.js';
|
||||
import GeolocationProperty from './GeolocationProperty.js';
|
||||
import BaseObject, {getChangeEventType} from './Object.js';
|
||||
import {listen} from './events.js';
|
||||
@@ -44,307 +43,293 @@ import {get as getProjection, getTransformFromProjections, identityTransform} fr
|
||||
* });
|
||||
*
|
||||
* @fires error
|
||||
* @constructor
|
||||
* @extends {module:ol/Object}
|
||||
* @param {module:ol/Geolocation~Options=} opt_options Options.
|
||||
* @api
|
||||
*/
|
||||
const Geolocation = function(opt_options) {
|
||||
|
||||
BaseObject.call(this);
|
||||
|
||||
const options = opt_options || {};
|
||||
class Geolocation extends BaseObject {
|
||||
|
||||
/**
|
||||
* The unprojected (EPSG:4326) device position.
|
||||
* @private
|
||||
* @type {module:ol/coordinate~Coordinate}
|
||||
* @param {module:ol/Geolocation~Options=} opt_options Options.
|
||||
*/
|
||||
this.position_ = null;
|
||||
constructor(opt_options) {
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {module:ol/proj~TransformFunction}
|
||||
*/
|
||||
this.transform_ = identityTransform;
|
||||
super();
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {number|undefined}
|
||||
*/
|
||||
this.watchId_ = undefined;
|
||||
const options = opt_options || {};
|
||||
|
||||
listen(
|
||||
this, getChangeEventType(GeolocationProperty.PROJECTION),
|
||||
this.handleProjectionChanged_, this);
|
||||
listen(
|
||||
this, getChangeEventType(GeolocationProperty.TRACKING),
|
||||
this.handleTrackingChanged_, this);
|
||||
/**
|
||||
* The unprojected (EPSG:4326) device position.
|
||||
* @private
|
||||
* @type {module:ol/coordinate~Coordinate}
|
||||
*/
|
||||
this.position_ = null;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {module:ol/proj~TransformFunction}
|
||||
*/
|
||||
this.transform_ = identityTransform;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {number|undefined}
|
||||
*/
|
||||
this.watchId_ = undefined;
|
||||
|
||||
listen(
|
||||
this, getChangeEventType(GeolocationProperty.PROJECTION),
|
||||
this.handleProjectionChanged_, this);
|
||||
listen(
|
||||
this, getChangeEventType(GeolocationProperty.TRACKING),
|
||||
this.handleTrackingChanged_, this);
|
||||
|
||||
if (options.projection !== undefined) {
|
||||
this.setProjection(options.projection);
|
||||
}
|
||||
if (options.trackingOptions !== undefined) {
|
||||
this.setTrackingOptions(options.trackingOptions);
|
||||
}
|
||||
|
||||
this.setTracking(options.tracking !== undefined ? options.tracking : false);
|
||||
|
||||
if (options.projection !== undefined) {
|
||||
this.setProjection(options.projection);
|
||||
}
|
||||
if (options.trackingOptions !== undefined) {
|
||||
this.setTrackingOptions(options.trackingOptions);
|
||||
}
|
||||
|
||||
this.setTracking(options.tracking !== undefined ? options.tracking : false);
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
disposeInternal() {
|
||||
this.setTracking(false);
|
||||
super.disposeInternal();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
inherits(Geolocation, BaseObject);
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
Geolocation.prototype.disposeInternal = function() {
|
||||
this.setTracking(false);
|
||||
BaseObject.prototype.disposeInternal.call(this);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
Geolocation.prototype.handleProjectionChanged_ = function() {
|
||||
const projection = this.getProjection();
|
||||
if (projection) {
|
||||
this.transform_ = getTransformFromProjections(
|
||||
getProjection('EPSG:4326'), projection);
|
||||
if (this.position_) {
|
||||
this.set(GeolocationProperty.POSITION, this.transform_(this.position_));
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
handleProjectionChanged_() {
|
||||
const projection = this.getProjection();
|
||||
if (projection) {
|
||||
this.transform_ = getTransformFromProjections(
|
||||
getProjection('EPSG:4326'), projection);
|
||||
if (this.position_) {
|
||||
this.set(GeolocationProperty.POSITION, this.transform_(this.position_));
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
Geolocation.prototype.handleTrackingChanged_ = function() {
|
||||
if (GEOLOCATION) {
|
||||
const tracking = this.getTracking();
|
||||
if (tracking && this.watchId_ === undefined) {
|
||||
this.watchId_ = navigator.geolocation.watchPosition(
|
||||
this.positionChange_.bind(this),
|
||||
this.positionError_.bind(this),
|
||||
this.getTrackingOptions());
|
||||
} else if (!tracking && this.watchId_ !== undefined) {
|
||||
navigator.geolocation.clearWatch(this.watchId_);
|
||||
this.watchId_ = undefined;
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
handleTrackingChanged_() {
|
||||
if (GEOLOCATION) {
|
||||
const tracking = this.getTracking();
|
||||
if (tracking && this.watchId_ === undefined) {
|
||||
this.watchId_ = navigator.geolocation.watchPosition(
|
||||
this.positionChange_.bind(this),
|
||||
this.positionError_.bind(this),
|
||||
this.getTrackingOptions());
|
||||
} else if (!tracking && this.watchId_ !== undefined) {
|
||||
navigator.geolocation.clearWatch(this.watchId_);
|
||||
this.watchId_ = undefined;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {GeolocationPosition} position position event.
|
||||
*/
|
||||
Geolocation.prototype.positionChange_ = function(position) {
|
||||
const coords = position.coords;
|
||||
this.set(GeolocationProperty.ACCURACY, coords.accuracy);
|
||||
this.set(GeolocationProperty.ALTITUDE,
|
||||
coords.altitude === null ? undefined : coords.altitude);
|
||||
this.set(GeolocationProperty.ALTITUDE_ACCURACY,
|
||||
coords.altitudeAccuracy === null ?
|
||||
undefined : coords.altitudeAccuracy);
|
||||
this.set(GeolocationProperty.HEADING, coords.heading === null ?
|
||||
undefined : toRadians(coords.heading));
|
||||
if (!this.position_) {
|
||||
this.position_ = [coords.longitude, coords.latitude];
|
||||
} else {
|
||||
this.position_[0] = coords.longitude;
|
||||
this.position_[1] = coords.latitude;
|
||||
/**
|
||||
* @private
|
||||
* @param {GeolocationPosition} position position event.
|
||||
*/
|
||||
positionChange_(position) {
|
||||
const coords = position.coords;
|
||||
this.set(GeolocationProperty.ACCURACY, coords.accuracy);
|
||||
this.set(GeolocationProperty.ALTITUDE,
|
||||
coords.altitude === null ? undefined : coords.altitude);
|
||||
this.set(GeolocationProperty.ALTITUDE_ACCURACY,
|
||||
coords.altitudeAccuracy === null ?
|
||||
undefined : coords.altitudeAccuracy);
|
||||
this.set(GeolocationProperty.HEADING, coords.heading === null ?
|
||||
undefined : toRadians(coords.heading));
|
||||
if (!this.position_) {
|
||||
this.position_ = [coords.longitude, coords.latitude];
|
||||
} else {
|
||||
this.position_[0] = coords.longitude;
|
||||
this.position_[1] = coords.latitude;
|
||||
}
|
||||
const projectedPosition = this.transform_(this.position_);
|
||||
this.set(GeolocationProperty.POSITION, projectedPosition);
|
||||
this.set(GeolocationProperty.SPEED,
|
||||
coords.speed === null ? undefined : coords.speed);
|
||||
const geometry = circularPolygon(this.position_, coords.accuracy);
|
||||
geometry.applyTransform(this.transform_);
|
||||
this.set(GeolocationProperty.ACCURACY_GEOMETRY, geometry);
|
||||
this.changed();
|
||||
}
|
||||
const projectedPosition = this.transform_(this.position_);
|
||||
this.set(GeolocationProperty.POSITION, projectedPosition);
|
||||
this.set(GeolocationProperty.SPEED,
|
||||
coords.speed === null ? undefined : coords.speed);
|
||||
const geometry = circularPolygon(this.position_, coords.accuracy);
|
||||
geometry.applyTransform(this.transform_);
|
||||
this.set(GeolocationProperty.ACCURACY_GEOMETRY, geometry);
|
||||
this.changed();
|
||||
};
|
||||
|
||||
/**
|
||||
* Triggered when the Geolocation returns an error.
|
||||
* @event error
|
||||
* @api
|
||||
*/
|
||||
/**
|
||||
* Triggered when the Geolocation returns an error.
|
||||
* @event error
|
||||
* @api
|
||||
*/
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {GeolocationPositionError} error error object.
|
||||
*/
|
||||
Geolocation.prototype.positionError_ = function(error) {
|
||||
error.type = EventType.ERROR;
|
||||
this.setTracking(false);
|
||||
this.dispatchEvent(/** @type {{type: string, target: undefined}} */ (error));
|
||||
};
|
||||
/**
|
||||
* @private
|
||||
* @param {GeolocationPositionError} error error object.
|
||||
*/
|
||||
positionError_(error) {
|
||||
error.type = EventType.ERROR;
|
||||
this.setTracking(false);
|
||||
this.dispatchEvent(/** @type {{type: string, target: undefined}} */ (error));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the accuracy of the position in meters.
|
||||
* @return {number|undefined} The accuracy of the position measurement in
|
||||
* meters.
|
||||
* @observable
|
||||
* @api
|
||||
*/
|
||||
getAccuracy() {
|
||||
return /** @type {number|undefined} */ (this.get(GeolocationProperty.ACCURACY));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a geometry of the position accuracy.
|
||||
* @return {?module:ol/geom/Polygon} A geometry of the position accuracy.
|
||||
* @observable
|
||||
* @api
|
||||
*/
|
||||
getAccuracyGeometry() {
|
||||
return (
|
||||
/** @type {?module:ol/geom/Polygon} */ (this.get(GeolocationProperty.ACCURACY_GEOMETRY) || null)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the altitude associated with the position.
|
||||
* @return {number|undefined} The altitude of the position in meters above mean
|
||||
* sea level.
|
||||
* @observable
|
||||
* @api
|
||||
*/
|
||||
getAltitude() {
|
||||
return /** @type {number|undefined} */ (this.get(GeolocationProperty.ALTITUDE));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the altitude accuracy of the position.
|
||||
* @return {number|undefined} The accuracy of the altitude measurement in
|
||||
* meters.
|
||||
* @observable
|
||||
* @api
|
||||
*/
|
||||
getAltitudeAccuracy() {
|
||||
return /** @type {number|undefined} */ (this.get(GeolocationProperty.ALTITUDE_ACCURACY));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the heading as radians clockwise from North.
|
||||
* Note: depending on the browser, the heading is only defined if the `enableHighAccuracy`
|
||||
* is set to `true` in the tracking options.
|
||||
* @return {number|undefined} The heading of the device in radians from north.
|
||||
* @observable
|
||||
* @api
|
||||
*/
|
||||
getHeading() {
|
||||
return /** @type {number|undefined} */ (this.get(GeolocationProperty.HEADING));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the position of the device.
|
||||
* @return {module:ol/coordinate~Coordinate|undefined} The current position of the device reported
|
||||
* in the current projection.
|
||||
* @observable
|
||||
* @api
|
||||
*/
|
||||
getPosition() {
|
||||
return (
|
||||
/** @type {module:ol/coordinate~Coordinate|undefined} */ (this.get(GeolocationProperty.POSITION))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the projection associated with the position.
|
||||
* @return {module:ol/proj/Projection|undefined} The projection the position is
|
||||
* reported in.
|
||||
* @observable
|
||||
* @api
|
||||
*/
|
||||
getProjection() {
|
||||
return (
|
||||
/** @type {module:ol/proj/Projection|undefined} */ (this.get(GeolocationProperty.PROJECTION))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the speed in meters per second.
|
||||
* @return {number|undefined} The instantaneous speed of the device in meters
|
||||
* per second.
|
||||
* @observable
|
||||
* @api
|
||||
*/
|
||||
getSpeed() {
|
||||
return /** @type {number|undefined} */ (this.get(GeolocationProperty.SPEED));
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the device location is being tracked.
|
||||
* @return {boolean} The device location is being tracked.
|
||||
* @observable
|
||||
* @api
|
||||
*/
|
||||
getTracking() {
|
||||
return /** @type {boolean} */ (this.get(GeolocationProperty.TRACKING));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the tracking options.
|
||||
* @see http://www.w3.org/TR/geolocation-API/#position-options
|
||||
* @return {GeolocationPositionOptions|undefined} PositionOptions as defined by
|
||||
* the [HTML5 Geolocation spec
|
||||
* ](http://www.w3.org/TR/geolocation-API/#position_options_interface).
|
||||
* @observable
|
||||
* @api
|
||||
*/
|
||||
getTrackingOptions() {
|
||||
return /** @type {GeolocationPositionOptions|undefined} */ (this.get(GeolocationProperty.TRACKING_OPTIONS));
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the projection to use for transforming the coordinates.
|
||||
* @param {module:ol/proj~ProjectionLike} projection The projection the position is
|
||||
* reported in.
|
||||
* @observable
|
||||
* @api
|
||||
*/
|
||||
setProjection(projection) {
|
||||
this.set(GeolocationProperty.PROJECTION, getProjection(projection));
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable or disable tracking.
|
||||
* @param {boolean} tracking Enable tracking.
|
||||
* @observable
|
||||
* @api
|
||||
*/
|
||||
setTracking(tracking) {
|
||||
this.set(GeolocationProperty.TRACKING, tracking);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the tracking options.
|
||||
* @see http://www.w3.org/TR/geolocation-API/#position-options
|
||||
* @param {GeolocationPositionOptions} options PositionOptions as defined by the
|
||||
* [HTML5 Geolocation spec
|
||||
* ](http://www.w3.org/TR/geolocation-API/#position_options_interface).
|
||||
* @observable
|
||||
* @api
|
||||
*/
|
||||
setTrackingOptions(options) {
|
||||
this.set(GeolocationProperty.TRACKING_OPTIONS, options);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the accuracy of the position in meters.
|
||||
* @return {number|undefined} The accuracy of the position measurement in
|
||||
* meters.
|
||||
* @observable
|
||||
* @api
|
||||
*/
|
||||
Geolocation.prototype.getAccuracy = function() {
|
||||
return /** @type {number|undefined} */ (this.get(GeolocationProperty.ACCURACY));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get a geometry of the position accuracy.
|
||||
* @return {?module:ol/geom/Polygon} A geometry of the position accuracy.
|
||||
* @observable
|
||||
* @api
|
||||
*/
|
||||
Geolocation.prototype.getAccuracyGeometry = function() {
|
||||
return (
|
||||
/** @type {?module:ol/geom/Polygon} */ (this.get(GeolocationProperty.ACCURACY_GEOMETRY) || null)
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get the altitude associated with the position.
|
||||
* @return {number|undefined} The altitude of the position in meters above mean
|
||||
* sea level.
|
||||
* @observable
|
||||
* @api
|
||||
*/
|
||||
Geolocation.prototype.getAltitude = function() {
|
||||
return /** @type {number|undefined} */ (this.get(GeolocationProperty.ALTITUDE));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get the altitude accuracy of the position.
|
||||
* @return {number|undefined} The accuracy of the altitude measurement in
|
||||
* meters.
|
||||
* @observable
|
||||
* @api
|
||||
*/
|
||||
Geolocation.prototype.getAltitudeAccuracy = function() {
|
||||
return /** @type {number|undefined} */ (this.get(GeolocationProperty.ALTITUDE_ACCURACY));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get the heading as radians clockwise from North.
|
||||
* Note: depending on the browser, the heading is only defined if the `enableHighAccuracy`
|
||||
* is set to `true` in the tracking options.
|
||||
* @return {number|undefined} The heading of the device in radians from north.
|
||||
* @observable
|
||||
* @api
|
||||
*/
|
||||
Geolocation.prototype.getHeading = function() {
|
||||
return /** @type {number|undefined} */ (this.get(GeolocationProperty.HEADING));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get the position of the device.
|
||||
* @return {module:ol/coordinate~Coordinate|undefined} The current position of the device reported
|
||||
* in the current projection.
|
||||
* @observable
|
||||
* @api
|
||||
*/
|
||||
Geolocation.prototype.getPosition = function() {
|
||||
return (
|
||||
/** @type {module:ol/coordinate~Coordinate|undefined} */ (this.get(GeolocationProperty.POSITION))
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get the projection associated with the position.
|
||||
* @return {module:ol/proj/Projection|undefined} The projection the position is
|
||||
* reported in.
|
||||
* @observable
|
||||
* @api
|
||||
*/
|
||||
Geolocation.prototype.getProjection = function() {
|
||||
return (
|
||||
/** @type {module:ol/proj/Projection|undefined} */ (this.get(GeolocationProperty.PROJECTION))
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get the speed in meters per second.
|
||||
* @return {number|undefined} The instantaneous speed of the device in meters
|
||||
* per second.
|
||||
* @observable
|
||||
* @api
|
||||
*/
|
||||
Geolocation.prototype.getSpeed = function() {
|
||||
return /** @type {number|undefined} */ (this.get(GeolocationProperty.SPEED));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Determine if the device location is being tracked.
|
||||
* @return {boolean} The device location is being tracked.
|
||||
* @observable
|
||||
* @api
|
||||
*/
|
||||
Geolocation.prototype.getTracking = function() {
|
||||
return /** @type {boolean} */ (this.get(GeolocationProperty.TRACKING));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get the tracking options.
|
||||
* @see http://www.w3.org/TR/geolocation-API/#position-options
|
||||
* @return {GeolocationPositionOptions|undefined} PositionOptions as defined by
|
||||
* the [HTML5 Geolocation spec
|
||||
* ](http://www.w3.org/TR/geolocation-API/#position_options_interface).
|
||||
* @observable
|
||||
* @api
|
||||
*/
|
||||
Geolocation.prototype.getTrackingOptions = function() {
|
||||
return /** @type {GeolocationPositionOptions|undefined} */ (this.get(GeolocationProperty.TRACKING_OPTIONS));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Set the projection to use for transforming the coordinates.
|
||||
* @param {module:ol/proj~ProjectionLike} projection The projection the position is
|
||||
* reported in.
|
||||
* @observable
|
||||
* @api
|
||||
*/
|
||||
Geolocation.prototype.setProjection = function(projection) {
|
||||
this.set(GeolocationProperty.PROJECTION, getProjection(projection));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Enable or disable tracking.
|
||||
* @param {boolean} tracking Enable tracking.
|
||||
* @observable
|
||||
* @api
|
||||
*/
|
||||
Geolocation.prototype.setTracking = function(tracking) {
|
||||
this.set(GeolocationProperty.TRACKING, tracking);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Set the tracking options.
|
||||
* @see http://www.w3.org/TR/geolocation-API/#position-options
|
||||
* @param {GeolocationPositionOptions} options PositionOptions as defined by the
|
||||
* [HTML5 Geolocation spec
|
||||
* ](http://www.w3.org/TR/geolocation-API/#position_options_interface).
|
||||
* @observable
|
||||
* @api
|
||||
*/
|
||||
Geolocation.prototype.setTrackingOptions = function(options) {
|
||||
this.set(GeolocationProperty.TRACKING_OPTIONS, options);
|
||||
};
|
||||
export default Geolocation;
|
||||
|
||||
1192
src/ol/Graticule.js
1192
src/ol/Graticule.js
File diff suppressed because it is too large
Load Diff
217
src/ol/Image.js
217
src/ol/Image.js
@@ -1,7 +1,6 @@
|
||||
/**
|
||||
* @module ol/Image
|
||||
*/
|
||||
import {inherits} from './util.js';
|
||||
import ImageBase from './ImageBase.js';
|
||||
import ImageState from './ImageState.js';
|
||||
import {listenOnce, unlistenByKey} from './events.js';
|
||||
@@ -28,132 +27,126 @@ import {getHeight} from './extent.js';
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
* @extends {module:ol/ImageBase}
|
||||
* @param {module:ol/extent~Extent} extent Extent.
|
||||
* @param {number|undefined} resolution Resolution.
|
||||
* @param {number} pixelRatio Pixel ratio.
|
||||
* @param {string} src Image source URI.
|
||||
* @param {?string} crossOrigin Cross origin.
|
||||
* @param {module:ol/Image~LoadFunction} imageLoadFunction Image load function.
|
||||
*/
|
||||
const ImageWrapper = function(extent, resolution, pixelRatio, src, crossOrigin, imageLoadFunction) {
|
||||
|
||||
ImageBase.call(this, extent, resolution, pixelRatio, ImageState.IDLE);
|
||||
class ImageWrapper extends ImageBase {
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {string}
|
||||
* @param {module:ol/extent~Extent} extent Extent.
|
||||
* @param {number|undefined} resolution Resolution.
|
||||
* @param {number} pixelRatio Pixel ratio.
|
||||
* @param {string} src Image source URI.
|
||||
* @param {?string} crossOrigin Cross origin.
|
||||
* @param {module:ol/Image~LoadFunction} imageLoadFunction Image load function.
|
||||
*/
|
||||
this.src_ = src;
|
||||
constructor(extent, resolution, pixelRatio, src, crossOrigin, imageLoadFunction) {
|
||||
|
||||
super(extent, resolution, pixelRatio, ImageState.IDLE);
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {string}
|
||||
*/
|
||||
this.src_ = src;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {HTMLCanvasElement|HTMLImageElement|HTMLVideoElement}
|
||||
*/
|
||||
this.image_ = new Image();
|
||||
if (crossOrigin !== null) {
|
||||
this.image_.crossOrigin = crossOrigin;
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {Array.<module:ol/events~EventsKey>}
|
||||
*/
|
||||
this.imageListenerKeys_ = null;
|
||||
|
||||
/**
|
||||
* @protected
|
||||
* @type {module:ol/ImageState}
|
||||
*/
|
||||
this.state = ImageState.IDLE;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {module:ol/Image~LoadFunction}
|
||||
*/
|
||||
this.imageLoadFunction_ = imageLoadFunction;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {HTMLCanvasElement|HTMLImageElement|HTMLVideoElement}
|
||||
*/
|
||||
this.image_ = new Image();
|
||||
if (crossOrigin !== null) {
|
||||
this.image_.crossOrigin = crossOrigin;
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {Array.<module:ol/events~EventsKey>}
|
||||
* @inheritDoc
|
||||
* @api
|
||||
*/
|
||||
this.imageListenerKeys_ = null;
|
||||
|
||||
/**
|
||||
* @protected
|
||||
* @type {module:ol/ImageState}
|
||||
*/
|
||||
this.state = ImageState.IDLE;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {module:ol/Image~LoadFunction}
|
||||
*/
|
||||
this.imageLoadFunction_ = imageLoadFunction;
|
||||
|
||||
};
|
||||
|
||||
inherits(ImageWrapper, ImageBase);
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @api
|
||||
*/
|
||||
ImageWrapper.prototype.getImage = function() {
|
||||
return this.image_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Tracks loading or read errors.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
ImageWrapper.prototype.handleImageError_ = function() {
|
||||
this.state = ImageState.ERROR;
|
||||
this.unlistenImage_();
|
||||
this.changed();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Tracks successful image load.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
ImageWrapper.prototype.handleImageLoad_ = function() {
|
||||
if (this.resolution === undefined) {
|
||||
this.resolution = getHeight(this.extent) / this.image_.height;
|
||||
getImage() {
|
||||
return this.image_;
|
||||
}
|
||||
this.state = ImageState.LOADED;
|
||||
this.unlistenImage_();
|
||||
this.changed();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Load the image or retry if loading previously failed.
|
||||
* Loading is taken care of by the tile queue, and calling this method is
|
||||
* only needed for preloading or for reloading in case of an error.
|
||||
* @override
|
||||
* @api
|
||||
*/
|
||||
ImageWrapper.prototype.load = function() {
|
||||
if (this.state == ImageState.IDLE || this.state == ImageState.ERROR) {
|
||||
this.state = ImageState.LOADING;
|
||||
/**
|
||||
* Tracks loading or read errors.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
handleImageError_() {
|
||||
this.state = ImageState.ERROR;
|
||||
this.unlistenImage_();
|
||||
this.changed();
|
||||
this.imageListenerKeys_ = [
|
||||
listenOnce(this.image_, EventType.ERROR,
|
||||
this.handleImageError_, this),
|
||||
listenOnce(this.image_, EventType.LOAD,
|
||||
this.handleImageLoad_, this)
|
||||
];
|
||||
this.imageLoadFunction_(this, this.src_);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Tracks successful image load.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
handleImageLoad_() {
|
||||
if (this.resolution === undefined) {
|
||||
this.resolution = getHeight(this.extent) / this.image_.height;
|
||||
}
|
||||
this.state = ImageState.LOADED;
|
||||
this.unlistenImage_();
|
||||
this.changed();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {HTMLCanvasElement|HTMLImageElement|HTMLVideoElement} image Image.
|
||||
*/
|
||||
ImageWrapper.prototype.setImage = function(image) {
|
||||
this.image_ = image;
|
||||
};
|
||||
/**
|
||||
* Load the image or retry if loading previously failed.
|
||||
* Loading is taken care of by the tile queue, and calling this method is
|
||||
* only needed for preloading or for reloading in case of an error.
|
||||
* @override
|
||||
* @api
|
||||
*/
|
||||
load() {
|
||||
if (this.state == ImageState.IDLE || this.state == ImageState.ERROR) {
|
||||
this.state = ImageState.LOADING;
|
||||
this.changed();
|
||||
this.imageListenerKeys_ = [
|
||||
listenOnce(this.image_, EventType.ERROR,
|
||||
this.handleImageError_, this),
|
||||
listenOnce(this.image_, EventType.LOAD,
|
||||
this.handleImageLoad_, this)
|
||||
];
|
||||
this.imageLoadFunction_(this, this.src_);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {HTMLCanvasElement|HTMLImageElement|HTMLVideoElement} image Image.
|
||||
*/
|
||||
setImage(image) {
|
||||
this.image_ = image;
|
||||
}
|
||||
|
||||
/**
|
||||
* Discards event handlers which listen for load completion or errors.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
unlistenImage_() {
|
||||
this.imageListenerKeys_.forEach(unlistenByKey);
|
||||
this.imageListenerKeys_ = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Discards event handlers which listen for load completion or errors.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
ImageWrapper.prototype.unlistenImage_ = function() {
|
||||
this.imageListenerKeys_.forEach(unlistenByKey);
|
||||
this.imageListenerKeys_ = null;
|
||||
};
|
||||
|
||||
export default ImageWrapper;
|
||||
|
||||
@@ -1,103 +1,97 @@
|
||||
/**
|
||||
* @module ol/ImageBase
|
||||
*/
|
||||
import {inherits} from './util.js';
|
||||
import EventTarget from './events/EventTarget.js';
|
||||
import EventType from './events/EventType.js';
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
* @abstract
|
||||
* @extends {module:ol/events/EventTarget}
|
||||
* @param {module:ol/extent~Extent} extent Extent.
|
||||
* @param {number|undefined} resolution Resolution.
|
||||
* @param {number} pixelRatio Pixel ratio.
|
||||
* @param {module:ol/ImageState} state State.
|
||||
*/
|
||||
const ImageBase = function(extent, resolution, pixelRatio, state) {
|
||||
class ImageBase extends EventTarget {
|
||||
|
||||
EventTarget.call(this);
|
||||
/**
|
||||
* @param {module:ol/extent~Extent} extent Extent.
|
||||
* @param {number|undefined} resolution Resolution.
|
||||
* @param {number} pixelRatio Pixel ratio.
|
||||
* @param {module:ol/ImageState} state State.
|
||||
*/
|
||||
constructor(extent, resolution, pixelRatio, state) {
|
||||
|
||||
super();
|
||||
|
||||
/**
|
||||
* @protected
|
||||
* @type {module:ol/extent~Extent}
|
||||
*/
|
||||
this.extent = extent;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {number}
|
||||
*/
|
||||
this.pixelRatio_ = pixelRatio;
|
||||
|
||||
/**
|
||||
* @protected
|
||||
* @type {number|undefined}
|
||||
*/
|
||||
this.resolution = resolution;
|
||||
|
||||
/**
|
||||
* @protected
|
||||
* @type {module:ol/ImageState}
|
||||
*/
|
||||
this.state = state;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @protected
|
||||
* @type {module:ol/extent~Extent}
|
||||
*/
|
||||
this.extent = extent;
|
||||
changed() {
|
||||
this.dispatchEvent(EventType.CHANGE);
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {number}
|
||||
* @return {module:ol/extent~Extent} Extent.
|
||||
*/
|
||||
this.pixelRatio_ = pixelRatio;
|
||||
getExtent() {
|
||||
return this.extent;
|
||||
}
|
||||
|
||||
/**
|
||||
* @protected
|
||||
* @type {number|undefined}
|
||||
* @abstract
|
||||
* @return {HTMLCanvasElement|HTMLImageElement|HTMLVideoElement} Image.
|
||||
*/
|
||||
this.resolution = resolution;
|
||||
getImage() {}
|
||||
|
||||
/**
|
||||
* @protected
|
||||
* @type {module:ol/ImageState}
|
||||
* @return {number} PixelRatio.
|
||||
*/
|
||||
this.state = state;
|
||||
getPixelRatio() {
|
||||
return this.pixelRatio_;
|
||||
}
|
||||
|
||||
};
|
||||
/**
|
||||
* @return {number} Resolution.
|
||||
*/
|
||||
getResolution() {
|
||||
return /** @type {number} */ (this.resolution);
|
||||
}
|
||||
|
||||
inherits(ImageBase, EventTarget);
|
||||
/**
|
||||
* @return {module:ol/ImageState} State.
|
||||
*/
|
||||
getState() {
|
||||
return this.state;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load not yet loaded URI.
|
||||
* @abstract
|
||||
*/
|
||||
load() {}
|
||||
}
|
||||
|
||||
/**
|
||||
* @protected
|
||||
*/
|
||||
ImageBase.prototype.changed = function() {
|
||||
this.dispatchEvent(EventType.CHANGE);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {module:ol/extent~Extent} Extent.
|
||||
*/
|
||||
ImageBase.prototype.getExtent = function() {
|
||||
return this.extent;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @abstract
|
||||
* @return {HTMLCanvasElement|HTMLImageElement|HTMLVideoElement} Image.
|
||||
*/
|
||||
ImageBase.prototype.getImage = function() {};
|
||||
|
||||
|
||||
/**
|
||||
* @return {number} PixelRatio.
|
||||
*/
|
||||
ImageBase.prototype.getPixelRatio = function() {
|
||||
return this.pixelRatio_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {number} Resolution.
|
||||
*/
|
||||
ImageBase.prototype.getResolution = function() {
|
||||
return /** @type {number} */ (this.resolution);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {module:ol/ImageState} State.
|
||||
*/
|
||||
ImageBase.prototype.getState = function() {
|
||||
return this.state;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Load not yet loaded URI.
|
||||
* @abstract
|
||||
*/
|
||||
ImageBase.prototype.load = function() {};
|
||||
|
||||
export default ImageBase;
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
/**
|
||||
* @module ol/ImageCanvas
|
||||
*/
|
||||
import {inherits} from './util.js';
|
||||
import ImageBase from './ImageBase.js';
|
||||
import ImageState from './ImageState.js';
|
||||
|
||||
@@ -16,87 +15,84 @@ import ImageState from './ImageState.js';
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
* @extends {module:ol/ImageBase}
|
||||
* @param {module:ol/extent~Extent} extent Extent.
|
||||
* @param {number} resolution Resolution.
|
||||
* @param {number} pixelRatio Pixel ratio.
|
||||
* @param {HTMLCanvasElement} canvas Canvas.
|
||||
* @param {module:ol/ImageCanvas~Loader=} opt_loader Optional loader function to
|
||||
* support asynchronous canvas drawing.
|
||||
*/
|
||||
const ImageCanvas = function(extent, resolution, pixelRatio, canvas, opt_loader) {
|
||||
class ImageCanvas extends ImageBase {
|
||||
|
||||
/**
|
||||
* Optional canvas loader function.
|
||||
* @type {?module:ol/ImageCanvas~Loader}
|
||||
* @private
|
||||
* @param {module:ol/extent~Extent} extent Extent.
|
||||
* @param {number} resolution Resolution.
|
||||
* @param {number} pixelRatio Pixel ratio.
|
||||
* @param {HTMLCanvasElement} canvas Canvas.
|
||||
* @param {module:ol/ImageCanvas~Loader=} opt_loader Optional loader function to
|
||||
* support asynchronous canvas drawing.
|
||||
*/
|
||||
this.loader_ = opt_loader !== undefined ? opt_loader : null;
|
||||
constructor(extent, resolution, pixelRatio, canvas, opt_loader) {
|
||||
|
||||
const state = opt_loader !== undefined ? ImageState.IDLE : ImageState.LOADED;
|
||||
const state = opt_loader !== undefined ? ImageState.IDLE : ImageState.LOADED;
|
||||
|
||||
ImageBase.call(this, extent, resolution, pixelRatio, state);
|
||||
super(extent, resolution, pixelRatio, state);
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {HTMLCanvasElement}
|
||||
*/
|
||||
this.canvas_ = canvas;
|
||||
/**
|
||||
* Optional canvas loader function.
|
||||
* @type {?module:ol/ImageCanvas~Loader}
|
||||
* @private
|
||||
*/
|
||||
this.loader_ = opt_loader !== undefined ? opt_loader : null;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {Error}
|
||||
*/
|
||||
this.error_ = null;
|
||||
/**
|
||||
* @private
|
||||
* @type {HTMLCanvasElement}
|
||||
*/
|
||||
this.canvas_ = canvas;
|
||||
|
||||
};
|
||||
/**
|
||||
* @private
|
||||
* @type {Error}
|
||||
*/
|
||||
this.error_ = null;
|
||||
|
||||
inherits(ImageCanvas, ImageBase);
|
||||
|
||||
|
||||
/**
|
||||
* Get any error associated with asynchronous rendering.
|
||||
* @return {Error} Any error that occurred during rendering.
|
||||
*/
|
||||
ImageCanvas.prototype.getError = function() {
|
||||
return this.error_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Handle async drawing complete.
|
||||
* @param {Error} err Any error during drawing.
|
||||
* @private
|
||||
*/
|
||||
ImageCanvas.prototype.handleLoad_ = function(err) {
|
||||
if (err) {
|
||||
this.error_ = err;
|
||||
this.state = ImageState.ERROR;
|
||||
} else {
|
||||
this.state = ImageState.LOADED;
|
||||
}
|
||||
this.changed();
|
||||
};
|
||||
|
||||
/**
|
||||
* Get any error associated with asynchronous rendering.
|
||||
* @return {Error} Any error that occurred during rendering.
|
||||
*/
|
||||
getError() {
|
||||
return this.error_;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
ImageCanvas.prototype.load = function() {
|
||||
if (this.state == ImageState.IDLE) {
|
||||
this.state = ImageState.LOADING;
|
||||
/**
|
||||
* Handle async drawing complete.
|
||||
* @param {Error} err Any error during drawing.
|
||||
* @private
|
||||
*/
|
||||
handleLoad_(err) {
|
||||
if (err) {
|
||||
this.error_ = err;
|
||||
this.state = ImageState.ERROR;
|
||||
} else {
|
||||
this.state = ImageState.LOADED;
|
||||
}
|
||||
this.changed();
|
||||
this.loader_(this.handleLoad_.bind(this));
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
load() {
|
||||
if (this.state == ImageState.IDLE) {
|
||||
this.state = ImageState.LOADING;
|
||||
this.changed();
|
||||
this.loader_(this.handleLoad_.bind(this));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {HTMLCanvasElement} Canvas element.
|
||||
*/
|
||||
getImage() {
|
||||
return this.canvas_;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return {HTMLCanvasElement} Canvas element.
|
||||
*/
|
||||
ImageCanvas.prototype.getImage = function() {
|
||||
return this.canvas_;
|
||||
};
|
||||
export default ImageCanvas;
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
/**
|
||||
* @module ol/ImageTile
|
||||
*/
|
||||
import {inherits} from './util.js';
|
||||
import Tile from './Tile.js';
|
||||
import TileState from './TileState.js';
|
||||
import {createCanvasContext2D} from './dom.js';
|
||||
@@ -14,159 +13,151 @@ import EventType from './events/EventType.js';
|
||||
* @api
|
||||
*/
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
* @extends {module:ol/Tile}
|
||||
* @param {module:ol/tilecoord~TileCoord} tileCoord Tile coordinate.
|
||||
* @param {module:ol/TileState} state State.
|
||||
* @param {string} src Image source URI.
|
||||
* @param {?string} crossOrigin Cross origin.
|
||||
* @param {module:ol/Tile~LoadFunction} tileLoadFunction Tile load function.
|
||||
* @param {module:ol/Tile~Options=} opt_options Tile options.
|
||||
*/
|
||||
const ImageTile = function(tileCoord, state, src, crossOrigin, tileLoadFunction, opt_options) {
|
||||
|
||||
Tile.call(this, tileCoord, state, opt_options);
|
||||
class ImageTile extends Tile {
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {?string}
|
||||
* @param {module:ol/tilecoord~TileCoord} tileCoord Tile coordinate.
|
||||
* @param {module:ol/TileState} state State.
|
||||
* @param {string} src Image source URI.
|
||||
* @param {?string} crossOrigin Cross origin.
|
||||
* @param {module:ol/Tile~LoadFunction} tileLoadFunction Tile load function.
|
||||
* @param {module:ol/Tile~Options=} opt_options Tile options.
|
||||
*/
|
||||
this.crossOrigin_ = crossOrigin;
|
||||
constructor(tileCoord, state, src, crossOrigin, tileLoadFunction, opt_options) {
|
||||
|
||||
super(tileCoord, state, opt_options);
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {?string}
|
||||
*/
|
||||
this.crossOrigin_ = crossOrigin;
|
||||
|
||||
/**
|
||||
* Image URI
|
||||
*
|
||||
* @private
|
||||
* @type {string}
|
||||
*/
|
||||
this.src_ = src;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {HTMLImageElement|HTMLCanvasElement}
|
||||
*/
|
||||
this.image_ = new Image();
|
||||
if (crossOrigin !== null) {
|
||||
this.image_.crossOrigin = crossOrigin;
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {Array.<module:ol/events~EventsKey>}
|
||||
*/
|
||||
this.imageListenerKeys_ = null;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {module:ol/Tile~LoadFunction}
|
||||
*/
|
||||
this.tileLoadFunction_ = tileLoadFunction;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Image URI
|
||||
* @inheritDoc
|
||||
*/
|
||||
disposeInternal() {
|
||||
if (this.state == TileState.LOADING) {
|
||||
this.unlistenImage_();
|
||||
this.image_ = getBlankImage();
|
||||
}
|
||||
if (this.interimTile) {
|
||||
this.interimTile.dispose();
|
||||
}
|
||||
this.state = TileState.ABORT;
|
||||
this.changed();
|
||||
super.disposeInternal();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the HTML image element for this tile (may be a Canvas, Image, or Video).
|
||||
* @return {HTMLCanvasElement|HTMLImageElement|HTMLVideoElement} Image.
|
||||
* @api
|
||||
*/
|
||||
getImage() {
|
||||
return this.image_;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
getKey() {
|
||||
return this.src_;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tracks loading or read errors.
|
||||
*
|
||||
* @private
|
||||
* @type {string}
|
||||
*/
|
||||
this.src_ = src;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {HTMLImageElement|HTMLCanvasElement}
|
||||
*/
|
||||
this.image_ = new Image();
|
||||
if (crossOrigin !== null) {
|
||||
this.image_.crossOrigin = crossOrigin;
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {Array.<module:ol/events~EventsKey>}
|
||||
*/
|
||||
this.imageListenerKeys_ = null;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {module:ol/Tile~LoadFunction}
|
||||
*/
|
||||
this.tileLoadFunction_ = tileLoadFunction;
|
||||
|
||||
};
|
||||
|
||||
inherits(ImageTile, Tile);
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
ImageTile.prototype.disposeInternal = function() {
|
||||
if (this.state == TileState.LOADING) {
|
||||
handleImageError_() {
|
||||
this.state = TileState.ERROR;
|
||||
this.unlistenImage_();
|
||||
this.image_ = getBlankImage();
|
||||
this.changed();
|
||||
}
|
||||
if (this.interimTile) {
|
||||
this.interimTile.dispose();
|
||||
|
||||
/**
|
||||
* Tracks successful image load.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
handleImageLoad_() {
|
||||
if (this.image_.naturalWidth && this.image_.naturalHeight) {
|
||||
this.state = TileState.LOADED;
|
||||
} else {
|
||||
this.state = TileState.EMPTY;
|
||||
}
|
||||
this.unlistenImage_();
|
||||
this.changed();
|
||||
}
|
||||
this.state = TileState.ABORT;
|
||||
this.changed();
|
||||
Tile.prototype.disposeInternal.call(this);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get the HTML image element for this tile (may be a Canvas, Image, or Video).
|
||||
* @return {HTMLCanvasElement|HTMLImageElement|HTMLVideoElement} Image.
|
||||
* @api
|
||||
*/
|
||||
ImageTile.prototype.getImage = function() {
|
||||
return this.image_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
ImageTile.prototype.getKey = function() {
|
||||
return this.src_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Tracks loading or read errors.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
ImageTile.prototype.handleImageError_ = function() {
|
||||
this.state = TileState.ERROR;
|
||||
this.unlistenImage_();
|
||||
this.image_ = getBlankImage();
|
||||
this.changed();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Tracks successful image load.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
ImageTile.prototype.handleImageLoad_ = function() {
|
||||
if (this.image_.naturalWidth && this.image_.naturalHeight) {
|
||||
this.state = TileState.LOADED;
|
||||
} else {
|
||||
this.state = TileState.EMPTY;
|
||||
}
|
||||
this.unlistenImage_();
|
||||
this.changed();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @api
|
||||
*/
|
||||
ImageTile.prototype.load = function() {
|
||||
if (this.state == TileState.ERROR) {
|
||||
this.state = TileState.IDLE;
|
||||
this.image_ = new Image();
|
||||
if (this.crossOrigin_ !== null) {
|
||||
this.image_.crossOrigin = this.crossOrigin_;
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @api
|
||||
*/
|
||||
load() {
|
||||
if (this.state == TileState.ERROR) {
|
||||
this.state = TileState.IDLE;
|
||||
this.image_ = new Image();
|
||||
if (this.crossOrigin_ !== null) {
|
||||
this.image_.crossOrigin = this.crossOrigin_;
|
||||
}
|
||||
}
|
||||
if (this.state == TileState.IDLE) {
|
||||
this.state = TileState.LOADING;
|
||||
this.changed();
|
||||
this.imageListenerKeys_ = [
|
||||
listenOnce(this.image_, EventType.ERROR,
|
||||
this.handleImageError_, this),
|
||||
listenOnce(this.image_, EventType.LOAD,
|
||||
this.handleImageLoad_, this)
|
||||
];
|
||||
this.tileLoadFunction_(this, this.src_);
|
||||
}
|
||||
}
|
||||
if (this.state == TileState.IDLE) {
|
||||
this.state = TileState.LOADING;
|
||||
this.changed();
|
||||
this.imageListenerKeys_ = [
|
||||
listenOnce(this.image_, EventType.ERROR,
|
||||
this.handleImageError_, this),
|
||||
listenOnce(this.image_, EventType.LOAD,
|
||||
this.handleImageLoad_, this)
|
||||
];
|
||||
this.tileLoadFunction_(this, this.src_);
|
||||
|
||||
/**
|
||||
* Discards event handlers which listen for load completion or errors.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
unlistenImage_() {
|
||||
this.imageListenerKeys_.forEach(unlistenByKey);
|
||||
this.imageListenerKeys_ = null;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Discards event handlers which listen for load completion or errors.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
ImageTile.prototype.unlistenImage_ = function() {
|
||||
this.imageListenerKeys_.forEach(unlistenByKey);
|
||||
this.imageListenerKeys_ = null;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
|
||||
@@ -6,124 +6,123 @@
|
||||
* @classdesc
|
||||
* Implementation of inertial deceleration for map movement.
|
||||
*
|
||||
* @constructor
|
||||
* @param {number} decay Rate of decay (must be negative).
|
||||
* @param {number} minVelocity Minimum velocity (pixels/millisecond).
|
||||
* @param {number} delay Delay to consider to calculate the kinetic
|
||||
* initial values (milliseconds).
|
||||
* @struct
|
||||
* @api
|
||||
*/
|
||||
const Kinetic = function(decay, minVelocity, delay) {
|
||||
class Kinetic {
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {number}
|
||||
* @param {number} decay Rate of decay (must be negative).
|
||||
* @param {number} minVelocity Minimum velocity (pixels/millisecond).
|
||||
* @param {number} delay Delay to consider to calculate the kinetic
|
||||
* initial values (milliseconds).
|
||||
*/
|
||||
this.decay_ = decay;
|
||||
constructor(decay, minVelocity, delay) {
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {number}
|
||||
*/
|
||||
this.minVelocity_ = minVelocity;
|
||||
/**
|
||||
* @private
|
||||
* @type {number}
|
||||
*/
|
||||
this.decay_ = decay;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {number}
|
||||
*/
|
||||
this.delay_ = delay;
|
||||
/**
|
||||
* @private
|
||||
* @type {number}
|
||||
*/
|
||||
this.minVelocity_ = minVelocity;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {Array.<number>}
|
||||
*/
|
||||
this.points_ = [];
|
||||
/**
|
||||
* @private
|
||||
* @type {number}
|
||||
*/
|
||||
this.delay_ = delay;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {number}
|
||||
*/
|
||||
this.angle_ = 0;
|
||||
/**
|
||||
* @private
|
||||
* @type {Array.<number>}
|
||||
*/
|
||||
this.points_ = [];
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {number}
|
||||
*/
|
||||
this.initialVelocity_ = 0;
|
||||
};
|
||||
/**
|
||||
* @private
|
||||
* @type {number}
|
||||
*/
|
||||
this.angle_ = 0;
|
||||
|
||||
|
||||
/**
|
||||
* FIXME empty description for jsdoc
|
||||
*/
|
||||
Kinetic.prototype.begin = function() {
|
||||
this.points_.length = 0;
|
||||
this.angle_ = 0;
|
||||
this.initialVelocity_ = 0;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {number} x X.
|
||||
* @param {number} y Y.
|
||||
*/
|
||||
Kinetic.prototype.update = function(x, y) {
|
||||
this.points_.push(x, y, Date.now());
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {boolean} Whether we should do kinetic animation.
|
||||
*/
|
||||
Kinetic.prototype.end = function() {
|
||||
if (this.points_.length < 6) {
|
||||
// at least 2 points are required (i.e. there must be at least 6 elements
|
||||
// in the array)
|
||||
return false;
|
||||
}
|
||||
const delay = Date.now() - this.delay_;
|
||||
const lastIndex = this.points_.length - 3;
|
||||
if (this.points_[lastIndex + 2] < delay) {
|
||||
// the last tracked point is too old, which means that the user stopped
|
||||
// panning before releasing the map
|
||||
return false;
|
||||
/**
|
||||
* @private
|
||||
* @type {number}
|
||||
*/
|
||||
this.initialVelocity_ = 0;
|
||||
}
|
||||
|
||||
// get the first point which still falls into the delay time
|
||||
let firstIndex = lastIndex - 3;
|
||||
while (firstIndex > 0 && this.points_[firstIndex + 2] > delay) {
|
||||
firstIndex -= 3;
|
||||
/**
|
||||
* FIXME empty description for jsdoc
|
||||
*/
|
||||
begin() {
|
||||
this.points_.length = 0;
|
||||
this.angle_ = 0;
|
||||
this.initialVelocity_ = 0;
|
||||
}
|
||||
|
||||
const duration = this.points_[lastIndex + 2] - this.points_[firstIndex + 2];
|
||||
// we don't want a duration of 0 (divide by zero)
|
||||
// we also make sure the user panned for a duration of at least one frame
|
||||
// (1/60s) to compute sane displacement values
|
||||
if (duration < 1000 / 60) {
|
||||
return false;
|
||||
/**
|
||||
* @param {number} x X.
|
||||
* @param {number} y Y.
|
||||
*/
|
||||
update(x, y) {
|
||||
this.points_.push(x, y, Date.now());
|
||||
}
|
||||
|
||||
const dx = this.points_[lastIndex] - this.points_[firstIndex];
|
||||
const dy = this.points_[lastIndex + 1] - this.points_[firstIndex + 1];
|
||||
this.angle_ = Math.atan2(dy, dx);
|
||||
this.initialVelocity_ = Math.sqrt(dx * dx + dy * dy) / duration;
|
||||
return this.initialVelocity_ > this.minVelocity_;
|
||||
};
|
||||
/**
|
||||
* @return {boolean} Whether we should do kinetic animation.
|
||||
*/
|
||||
end() {
|
||||
if (this.points_.length < 6) {
|
||||
// at least 2 points are required (i.e. there must be at least 6 elements
|
||||
// in the array)
|
||||
return false;
|
||||
}
|
||||
const delay = Date.now() - this.delay_;
|
||||
const lastIndex = this.points_.length - 3;
|
||||
if (this.points_[lastIndex + 2] < delay) {
|
||||
// the last tracked point is too old, which means that the user stopped
|
||||
// panning before releasing the map
|
||||
return false;
|
||||
}
|
||||
|
||||
// get the first point which still falls into the delay time
|
||||
let firstIndex = lastIndex - 3;
|
||||
while (firstIndex > 0 && this.points_[firstIndex + 2] > delay) {
|
||||
firstIndex -= 3;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {number} Total distance travelled (pixels).
|
||||
*/
|
||||
Kinetic.prototype.getDistance = function() {
|
||||
return (this.minVelocity_ - this.initialVelocity_) / this.decay_;
|
||||
};
|
||||
const duration = this.points_[lastIndex + 2] - this.points_[firstIndex + 2];
|
||||
// we don't want a duration of 0 (divide by zero)
|
||||
// we also make sure the user panned for a duration of at least one frame
|
||||
// (1/60s) to compute sane displacement values
|
||||
if (duration < 1000 / 60) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const dx = this.points_[lastIndex] - this.points_[firstIndex];
|
||||
const dy = this.points_[lastIndex + 1] - this.points_[firstIndex + 1];
|
||||
this.angle_ = Math.atan2(dy, dx);
|
||||
this.initialVelocity_ = Math.sqrt(dx * dx + dy * dy) / duration;
|
||||
return this.initialVelocity_ > this.minVelocity_;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {number} Total distance travelled (pixels).
|
||||
*/
|
||||
getDistance() {
|
||||
return (this.minVelocity_ - this.initialVelocity_) / this.decay_;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {number} Angle of the kinetic panning animation (radians).
|
||||
*/
|
||||
getAngle() {
|
||||
return this.angle_;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {number} Angle of the kinetic panning animation (radians).
|
||||
*/
|
||||
Kinetic.prototype.getAngle = function() {
|
||||
return this.angle_;
|
||||
};
|
||||
export default Kinetic;
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
/**
|
||||
* @module ol/Map
|
||||
*/
|
||||
import {inherits} from './util.js';
|
||||
import PluggableMap from './PluggableMap.js';
|
||||
import {defaults as defaultControls} from './control/util.js';
|
||||
import {defaults as defaultInteractions} from './interaction.js';
|
||||
@@ -57,38 +56,40 @@ import CanvasVectorTileLayerRenderer from './renderer/canvas/VectorTileLayer.js'
|
||||
* options or added with `addLayer` can be groups, which can contain further
|
||||
* groups, and so on.
|
||||
*
|
||||
* @constructor
|
||||
* @extends {module:ol/PluggableMap}
|
||||
* @param {module:ol/PluggableMap~MapOptions} options Map options.
|
||||
* @fires module:ol/MapBrowserEvent~MapBrowserEvent
|
||||
* @fires module:ol/MapEvent~MapEvent
|
||||
* @fires module:ol/render/Event~RenderEvent#postcompose
|
||||
* @fires module:ol/render/Event~RenderEvent#precompose
|
||||
* @api
|
||||
*/
|
||||
const Map = function(options) {
|
||||
options = assign({}, options);
|
||||
if (!options.controls) {
|
||||
options.controls = defaultControls();
|
||||
}
|
||||
if (!options.interactions) {
|
||||
options.interactions = defaultInteractions();
|
||||
class Map extends PluggableMap {
|
||||
|
||||
/**
|
||||
* @param {module:ol/PluggableMap~MapOptions} options Map options.
|
||||
*/
|
||||
constructor(options) {
|
||||
options = assign({}, options);
|
||||
if (!options.controls) {
|
||||
options.controls = defaultControls();
|
||||
}
|
||||
if (!options.interactions) {
|
||||
options.interactions = defaultInteractions();
|
||||
}
|
||||
|
||||
super(options);
|
||||
}
|
||||
|
||||
PluggableMap.call(this, options);
|
||||
};
|
||||
createRenderer() {
|
||||
const renderer = new CanvasMapRenderer(this);
|
||||
renderer.registerLayerRenderers([
|
||||
CanvasImageLayerRenderer,
|
||||
CanvasTileLayerRenderer,
|
||||
CanvasVectorLayerRenderer,
|
||||
CanvasVectorTileLayerRenderer
|
||||
]);
|
||||
return renderer;
|
||||
}
|
||||
}
|
||||
|
||||
inherits(Map, PluggableMap);
|
||||
|
||||
Map.prototype.createRenderer = function() {
|
||||
const renderer = new CanvasMapRenderer(this);
|
||||
renderer.registerLayerRenderers([
|
||||
CanvasImageLayerRenderer,
|
||||
CanvasTileLayerRenderer,
|
||||
CanvasVectorLayerRenderer,
|
||||
CanvasVectorTileLayerRenderer
|
||||
]);
|
||||
return renderer;
|
||||
};
|
||||
|
||||
export default Map;
|
||||
|
||||
@@ -1,82 +1,81 @@
|
||||
/**
|
||||
* @module ol/MapBrowserEvent
|
||||
*/
|
||||
import {inherits} from './util.js';
|
||||
import MapEvent from './MapEvent.js';
|
||||
|
||||
/**
|
||||
* @classdesc
|
||||
* Events emitted as map browser events are instances of this type.
|
||||
* See {@link module:ol/Map~Map} for which events trigger a map browser event.
|
||||
*
|
||||
* @constructor
|
||||
* @extends {module:ol/MapEvent}
|
||||
* @param {string} type Event type.
|
||||
* @param {module:ol/PluggableMap} map Map.
|
||||
* @param {Event} browserEvent Browser event.
|
||||
* @param {boolean=} opt_dragging Is the map currently being dragged?
|
||||
* @param {?module:ol/PluggableMap~FrameState=} opt_frameState Frame state.
|
||||
*/
|
||||
const MapBrowserEvent = function(type, map, browserEvent, opt_dragging, opt_frameState) {
|
||||
|
||||
MapEvent.call(this, type, map, opt_frameState);
|
||||
class MapBrowserEvent extends MapEvent {
|
||||
|
||||
/**
|
||||
* The original browser event.
|
||||
* @const
|
||||
* @type {Event}
|
||||
* @api
|
||||
* @param {string} type Event type.
|
||||
* @param {module:ol/PluggableMap} map Map.
|
||||
* @param {Event} browserEvent Browser event.
|
||||
* @param {boolean=} opt_dragging Is the map currently being dragged?
|
||||
* @param {?module:ol/PluggableMap~FrameState=} opt_frameState Frame state.
|
||||
*/
|
||||
this.originalEvent = browserEvent;
|
||||
constructor(type, map, browserEvent, opt_dragging, opt_frameState) {
|
||||
|
||||
super(type, map, opt_frameState);
|
||||
|
||||
/**
|
||||
* The original browser event.
|
||||
* @const
|
||||
* @type {Event}
|
||||
* @api
|
||||
*/
|
||||
this.originalEvent = browserEvent;
|
||||
|
||||
/**
|
||||
* The map pixel relative to the viewport corresponding to the original browser event.
|
||||
* @type {module:ol~Pixel}
|
||||
* @api
|
||||
*/
|
||||
this.pixel = map.getEventPixel(browserEvent);
|
||||
|
||||
/**
|
||||
* The coordinate in view projection corresponding to the original browser event.
|
||||
* @type {module:ol/coordinate~Coordinate}
|
||||
* @api
|
||||
*/
|
||||
this.coordinate = map.getCoordinateFromPixel(this.pixel);
|
||||
|
||||
/**
|
||||
* Indicates if the map is currently being dragged. Only set for
|
||||
* `POINTERDRAG` and `POINTERMOVE` events. Default is `false`.
|
||||
*
|
||||
* @type {boolean}
|
||||
* @api
|
||||
*/
|
||||
this.dragging = opt_dragging !== undefined ? opt_dragging : false;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* The map pixel relative to the viewport corresponding to the original browser event.
|
||||
* @type {module:ol~Pixel}
|
||||
* Prevents the default browser action.
|
||||
* @see https://developer.mozilla.org/en-US/docs/Web/API/event.preventDefault
|
||||
* @override
|
||||
* @api
|
||||
*/
|
||||
this.pixel = map.getEventPixel(browserEvent);
|
||||
preventDefault() {
|
||||
super.preventDefault();
|
||||
this.originalEvent.preventDefault();
|
||||
}
|
||||
|
||||
/**
|
||||
* The coordinate in view projection corresponding to the original browser event.
|
||||
* @type {module:ol/coordinate~Coordinate}
|
||||
* Prevents further propagation of the current event.
|
||||
* @see https://developer.mozilla.org/en-US/docs/Web/API/event.stopPropagation
|
||||
* @override
|
||||
* @api
|
||||
*/
|
||||
this.coordinate = map.getCoordinateFromPixel(this.pixel);
|
||||
|
||||
/**
|
||||
* Indicates if the map is currently being dragged. Only set for
|
||||
* `POINTERDRAG` and `POINTERMOVE` events. Default is `false`.
|
||||
*
|
||||
* @type {boolean}
|
||||
* @api
|
||||
*/
|
||||
this.dragging = opt_dragging !== undefined ? opt_dragging : false;
|
||||
|
||||
};
|
||||
|
||||
inherits(MapBrowserEvent, MapEvent);
|
||||
stopPropagation() {
|
||||
super.stopPropagation();
|
||||
this.originalEvent.stopPropagation();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Prevents the default browser action.
|
||||
* @see https://developer.mozilla.org/en-US/docs/Web/API/event.preventDefault
|
||||
* @override
|
||||
* @api
|
||||
*/
|
||||
MapBrowserEvent.prototype.preventDefault = function() {
|
||||
MapEvent.prototype.preventDefault.call(this);
|
||||
this.originalEvent.preventDefault();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Prevents further propagation of the current event.
|
||||
* @see https://developer.mozilla.org/en-US/docs/Web/API/event.stopPropagation
|
||||
* @override
|
||||
* @api
|
||||
*/
|
||||
MapBrowserEvent.prototype.stopPropagation = function() {
|
||||
MapEvent.prototype.stopPropagation.call(this);
|
||||
this.originalEvent.stopPropagation();
|
||||
};
|
||||
export default MapBrowserEvent;
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
/**
|
||||
* @module ol/MapBrowserEventHandler
|
||||
*/
|
||||
import {inherits} from './util.js';
|
||||
import {DEVICE_PIXEL_RATIO} from './has.js';
|
||||
import MapBrowserEventType from './MapBrowserEventType.js';
|
||||
import MapBrowserPointerEvent from './MapBrowserPointerEvent.js';
|
||||
@@ -10,327 +9,317 @@ import EventTarget from './events/EventTarget.js';
|
||||
import PointerEventType from './pointer/EventType.js';
|
||||
import PointerEventHandler from './pointer/PointerEventHandler.js';
|
||||
|
||||
/**
|
||||
* @param {module:ol/PluggableMap} map The map with the viewport to
|
||||
* listen to events on.
|
||||
* @param {number=} moveTolerance The minimal distance the pointer must travel
|
||||
* to trigger a move.
|
||||
* @constructor
|
||||
* @extends {module:ol/events/EventTarget}
|
||||
*/
|
||||
const MapBrowserEventHandler = function(map, moveTolerance) {
|
||||
|
||||
EventTarget.call(this);
|
||||
class MapBrowserEventHandler extends EventTarget {
|
||||
|
||||
/**
|
||||
* This is the element that we will listen to the real events on.
|
||||
* @type {module:ol/PluggableMap}
|
||||
* @private
|
||||
* @param {module:ol/PluggableMap} map The map with the viewport to listen to events on.
|
||||
* @param {number=} moveTolerance The minimal distance the pointer must travel to trigger a move.
|
||||
*/
|
||||
this.map_ = map;
|
||||
constructor(map, moveTolerance) {
|
||||
|
||||
/**
|
||||
* @type {number}
|
||||
* @private
|
||||
*/
|
||||
this.clickTimeoutId_ = 0;
|
||||
super();
|
||||
|
||||
/**
|
||||
* @type {boolean}
|
||||
* @private
|
||||
*/
|
||||
this.dragging_ = false;
|
||||
/**
|
||||
* This is the element that we will listen to the real events on.
|
||||
* @type {module:ol/PluggableMap}
|
||||
* @private
|
||||
*/
|
||||
this.map_ = map;
|
||||
|
||||
/**
|
||||
* @type {!Array.<module:ol/events~EventsKey>}
|
||||
* @private
|
||||
*/
|
||||
this.dragListenerKeys_ = [];
|
||||
|
||||
/**
|
||||
* @type {number}
|
||||
* @private
|
||||
*/
|
||||
this.moveTolerance_ = moveTolerance ?
|
||||
moveTolerance * DEVICE_PIXEL_RATIO : DEVICE_PIXEL_RATIO;
|
||||
|
||||
/**
|
||||
* The most recent "down" type event (or null if none have occurred).
|
||||
* Set on pointerdown.
|
||||
* @type {module:ol/pointer/PointerEvent}
|
||||
* @private
|
||||
*/
|
||||
this.down_ = null;
|
||||
|
||||
const element = this.map_.getViewport();
|
||||
|
||||
/**
|
||||
* @type {number}
|
||||
* @private
|
||||
*/
|
||||
this.activePointers_ = 0;
|
||||
|
||||
/**
|
||||
* @type {!Object.<number, boolean>}
|
||||
* @private
|
||||
*/
|
||||
this.trackedTouches_ = {};
|
||||
|
||||
/**
|
||||
* Event handler which generates pointer events for
|
||||
* the viewport element.
|
||||
*
|
||||
* @type {module:ol/pointer/PointerEventHandler}
|
||||
* @private
|
||||
*/
|
||||
this.pointerEventHandler_ = new PointerEventHandler(element);
|
||||
|
||||
/**
|
||||
* Event handler which generates pointer events for
|
||||
* the document (used when dragging).
|
||||
*
|
||||
* @type {module:ol/pointer/PointerEventHandler}
|
||||
* @private
|
||||
*/
|
||||
this.documentPointerEventHandler_ = null;
|
||||
|
||||
/**
|
||||
* @type {?module:ol/events~EventsKey}
|
||||
* @private
|
||||
*/
|
||||
this.pointerdownListenerKey_ = listen(this.pointerEventHandler_,
|
||||
PointerEventType.POINTERDOWN,
|
||||
this.handlePointerDown_, this);
|
||||
|
||||
/**
|
||||
* @type {?module:ol/events~EventsKey}
|
||||
* @private
|
||||
*/
|
||||
this.relayedListenerKey_ = listen(this.pointerEventHandler_,
|
||||
PointerEventType.POINTERMOVE,
|
||||
this.relayEvent_, this);
|
||||
|
||||
};
|
||||
|
||||
inherits(MapBrowserEventHandler, EventTarget);
|
||||
|
||||
|
||||
/**
|
||||
* @param {module:ol/pointer/PointerEvent} pointerEvent Pointer
|
||||
* event.
|
||||
* @private
|
||||
*/
|
||||
MapBrowserEventHandler.prototype.emulateClick_ = function(pointerEvent) {
|
||||
let newEvent = new MapBrowserPointerEvent(
|
||||
MapBrowserEventType.CLICK, this.map_, pointerEvent);
|
||||
this.dispatchEvent(newEvent);
|
||||
if (this.clickTimeoutId_ !== 0) {
|
||||
// double-click
|
||||
clearTimeout(this.clickTimeoutId_);
|
||||
/**
|
||||
* @type {number}
|
||||
* @private
|
||||
*/
|
||||
this.clickTimeoutId_ = 0;
|
||||
newEvent = new MapBrowserPointerEvent(
|
||||
MapBrowserEventType.DBLCLICK, this.map_, pointerEvent);
|
||||
|
||||
/**
|
||||
* @type {boolean}
|
||||
* @private
|
||||
*/
|
||||
this.dragging_ = false;
|
||||
|
||||
/**
|
||||
* @type {!Array.<module:ol/events~EventsKey>}
|
||||
* @private
|
||||
*/
|
||||
this.dragListenerKeys_ = [];
|
||||
|
||||
/**
|
||||
* @type {number}
|
||||
* @private
|
||||
*/
|
||||
this.moveTolerance_ = moveTolerance ?
|
||||
moveTolerance * DEVICE_PIXEL_RATIO : DEVICE_PIXEL_RATIO;
|
||||
|
||||
/**
|
||||
* The most recent "down" type event (or null if none have occurred).
|
||||
* Set on pointerdown.
|
||||
* @type {module:ol/pointer/PointerEvent}
|
||||
* @private
|
||||
*/
|
||||
this.down_ = null;
|
||||
|
||||
const element = this.map_.getViewport();
|
||||
|
||||
/**
|
||||
* @type {number}
|
||||
* @private
|
||||
*/
|
||||
this.activePointers_ = 0;
|
||||
|
||||
/**
|
||||
* @type {!Object.<number, boolean>}
|
||||
* @private
|
||||
*/
|
||||
this.trackedTouches_ = {};
|
||||
|
||||
/**
|
||||
* Event handler which generates pointer events for
|
||||
* the viewport element.
|
||||
*
|
||||
* @type {module:ol/pointer/PointerEventHandler}
|
||||
* @private
|
||||
*/
|
||||
this.pointerEventHandler_ = new PointerEventHandler(element);
|
||||
|
||||
/**
|
||||
* Event handler which generates pointer events for
|
||||
* the document (used when dragging).
|
||||
*
|
||||
* @type {module:ol/pointer/PointerEventHandler}
|
||||
* @private
|
||||
*/
|
||||
this.documentPointerEventHandler_ = null;
|
||||
|
||||
/**
|
||||
* @type {?module:ol/events~EventsKey}
|
||||
* @private
|
||||
*/
|
||||
this.pointerdownListenerKey_ = listen(this.pointerEventHandler_,
|
||||
PointerEventType.POINTERDOWN,
|
||||
this.handlePointerDown_, this);
|
||||
|
||||
/**
|
||||
* @type {?module:ol/events~EventsKey}
|
||||
* @private
|
||||
*/
|
||||
this.relayedListenerKey_ = listen(this.pointerEventHandler_,
|
||||
PointerEventType.POINTERMOVE,
|
||||
this.relayEvent_, this);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {module:ol/pointer/PointerEvent} pointerEvent Pointer
|
||||
* event.
|
||||
* @private
|
||||
*/
|
||||
emulateClick_(pointerEvent) {
|
||||
let newEvent = new MapBrowserPointerEvent(
|
||||
MapBrowserEventType.CLICK, this.map_, pointerEvent);
|
||||
this.dispatchEvent(newEvent);
|
||||
} else {
|
||||
// click
|
||||
this.clickTimeoutId_ = setTimeout(function() {
|
||||
if (this.clickTimeoutId_ !== 0) {
|
||||
// double-click
|
||||
clearTimeout(this.clickTimeoutId_);
|
||||
this.clickTimeoutId_ = 0;
|
||||
const newEvent = new MapBrowserPointerEvent(
|
||||
MapBrowserEventType.SINGLECLICK, this.map_, pointerEvent);
|
||||
newEvent = new MapBrowserPointerEvent(
|
||||
MapBrowserEventType.DBLCLICK, this.map_, pointerEvent);
|
||||
this.dispatchEvent(newEvent);
|
||||
}.bind(this), 250);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Keeps track on how many pointers are currently active.
|
||||
*
|
||||
* @param {module:ol/pointer/PointerEvent} pointerEvent Pointer
|
||||
* event.
|
||||
* @private
|
||||
*/
|
||||
MapBrowserEventHandler.prototype.updateActivePointers_ = function(pointerEvent) {
|
||||
const event = pointerEvent;
|
||||
|
||||
if (event.type == MapBrowserEventType.POINTERUP ||
|
||||
event.type == MapBrowserEventType.POINTERCANCEL) {
|
||||
delete this.trackedTouches_[event.pointerId];
|
||||
} else if (event.type == MapBrowserEventType.POINTERDOWN) {
|
||||
this.trackedTouches_[event.pointerId] = true;
|
||||
}
|
||||
this.activePointers_ = Object.keys(this.trackedTouches_).length;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {module:ol/pointer/PointerEvent} pointerEvent Pointer
|
||||
* event.
|
||||
* @private
|
||||
*/
|
||||
MapBrowserEventHandler.prototype.handlePointerUp_ = function(pointerEvent) {
|
||||
this.updateActivePointers_(pointerEvent);
|
||||
const newEvent = new MapBrowserPointerEvent(
|
||||
MapBrowserEventType.POINTERUP, this.map_, pointerEvent);
|
||||
this.dispatchEvent(newEvent);
|
||||
|
||||
// We emulate click events on left mouse button click, touch contact, and pen
|
||||
// contact. isMouseActionButton returns true in these cases (evt.button is set
|
||||
// to 0).
|
||||
// See http://www.w3.org/TR/pointerevents/#button-states
|
||||
// We only fire click, singleclick, and doubleclick if nobody has called
|
||||
// event.stopPropagation() or event.preventDefault().
|
||||
if (!newEvent.propagationStopped && !this.dragging_ && this.isMouseActionButton_(pointerEvent)) {
|
||||
this.emulateClick_(this.down_);
|
||||
} else {
|
||||
// click
|
||||
this.clickTimeoutId_ = setTimeout(function() {
|
||||
this.clickTimeoutId_ = 0;
|
||||
const newEvent = new MapBrowserPointerEvent(
|
||||
MapBrowserEventType.SINGLECLICK, this.map_, pointerEvent);
|
||||
this.dispatchEvent(newEvent);
|
||||
}.bind(this), 250);
|
||||
}
|
||||
}
|
||||
|
||||
if (this.activePointers_ === 0) {
|
||||
/**
|
||||
* Keeps track on how many pointers are currently active.
|
||||
*
|
||||
* @param {module:ol/pointer/PointerEvent} pointerEvent Pointer
|
||||
* event.
|
||||
* @private
|
||||
*/
|
||||
updateActivePointers_(pointerEvent) {
|
||||
const event = pointerEvent;
|
||||
|
||||
if (event.type == MapBrowserEventType.POINTERUP ||
|
||||
event.type == MapBrowserEventType.POINTERCANCEL) {
|
||||
delete this.trackedTouches_[event.pointerId];
|
||||
} else if (event.type == MapBrowserEventType.POINTERDOWN) {
|
||||
this.trackedTouches_[event.pointerId] = true;
|
||||
}
|
||||
this.activePointers_ = Object.keys(this.trackedTouches_).length;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {module:ol/pointer/PointerEvent} pointerEvent Pointer
|
||||
* event.
|
||||
* @private
|
||||
*/
|
||||
handlePointerUp_(pointerEvent) {
|
||||
this.updateActivePointers_(pointerEvent);
|
||||
const newEvent = new MapBrowserPointerEvent(
|
||||
MapBrowserEventType.POINTERUP, this.map_, pointerEvent);
|
||||
this.dispatchEvent(newEvent);
|
||||
|
||||
// We emulate click events on left mouse button click, touch contact, and pen
|
||||
// contact. isMouseActionButton returns true in these cases (evt.button is set
|
||||
// to 0).
|
||||
// See http://www.w3.org/TR/pointerevents/#button-states
|
||||
// We only fire click, singleclick, and doubleclick if nobody has called
|
||||
// event.stopPropagation() or event.preventDefault().
|
||||
if (!newEvent.propagationStopped && !this.dragging_ && this.isMouseActionButton_(pointerEvent)) {
|
||||
this.emulateClick_(this.down_);
|
||||
}
|
||||
|
||||
if (this.activePointers_ === 0) {
|
||||
this.dragListenerKeys_.forEach(unlistenByKey);
|
||||
this.dragListenerKeys_.length = 0;
|
||||
this.dragging_ = false;
|
||||
this.down_ = null;
|
||||
this.documentPointerEventHandler_.dispose();
|
||||
this.documentPointerEventHandler_ = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {module:ol/pointer/PointerEvent} pointerEvent Pointer
|
||||
* event.
|
||||
* @return {boolean} If the left mouse button was pressed.
|
||||
* @private
|
||||
*/
|
||||
isMouseActionButton_(pointerEvent) {
|
||||
return pointerEvent.button === 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {module:ol/pointer/PointerEvent} pointerEvent Pointer
|
||||
* event.
|
||||
* @private
|
||||
*/
|
||||
handlePointerDown_(pointerEvent) {
|
||||
this.updateActivePointers_(pointerEvent);
|
||||
const newEvent = new MapBrowserPointerEvent(
|
||||
MapBrowserEventType.POINTERDOWN, this.map_, pointerEvent);
|
||||
this.dispatchEvent(newEvent);
|
||||
|
||||
this.down_ = pointerEvent;
|
||||
|
||||
if (this.dragListenerKeys_.length === 0) {
|
||||
/* Set up a pointer event handler on the `document`,
|
||||
* which is required when the pointer is moved outside
|
||||
* the viewport when dragging.
|
||||
*/
|
||||
this.documentPointerEventHandler_ =
|
||||
new PointerEventHandler(document);
|
||||
|
||||
this.dragListenerKeys_.push(
|
||||
listen(this.documentPointerEventHandler_,
|
||||
MapBrowserEventType.POINTERMOVE,
|
||||
this.handlePointerMove_, this),
|
||||
listen(this.documentPointerEventHandler_,
|
||||
MapBrowserEventType.POINTERUP,
|
||||
this.handlePointerUp_, this),
|
||||
/* Note that the listener for `pointercancel is set up on
|
||||
* `pointerEventHandler_` and not `documentPointerEventHandler_` like
|
||||
* the `pointerup` and `pointermove` listeners.
|
||||
*
|
||||
* The reason for this is the following: `TouchSource.vacuumTouches_()`
|
||||
* issues `pointercancel` events, when there was no `touchend` for a
|
||||
* `touchstart`. Now, let's say a first `touchstart` is registered on
|
||||
* `pointerEventHandler_`. The `documentPointerEventHandler_` is set up.
|
||||
* But `documentPointerEventHandler_` doesn't know about the first
|
||||
* `touchstart`. If there is no `touchend` for the `touchstart`, we can
|
||||
* only receive a `touchcancel` from `pointerEventHandler_`, because it is
|
||||
* only registered there.
|
||||
*/
|
||||
listen(this.pointerEventHandler_,
|
||||
MapBrowserEventType.POINTERCANCEL,
|
||||
this.handlePointerUp_, this)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {module:ol/pointer/PointerEvent} pointerEvent Pointer
|
||||
* event.
|
||||
* @private
|
||||
*/
|
||||
handlePointerMove_(pointerEvent) {
|
||||
// Between pointerdown and pointerup, pointermove events are triggered.
|
||||
// To avoid a 'false' touchmove event to be dispatched, we test if the pointer
|
||||
// moved a significant distance.
|
||||
if (this.isMoving_(pointerEvent)) {
|
||||
this.dragging_ = true;
|
||||
const newEvent = new MapBrowserPointerEvent(
|
||||
MapBrowserEventType.POINTERDRAG, this.map_, pointerEvent,
|
||||
this.dragging_);
|
||||
this.dispatchEvent(newEvent);
|
||||
}
|
||||
|
||||
// Some native android browser triggers mousemove events during small period
|
||||
// of time. See: https://code.google.com/p/android/issues/detail?id=5491 or
|
||||
// https://code.google.com/p/android/issues/detail?id=19827
|
||||
// ex: Galaxy Tab P3110 + Android 4.1.1
|
||||
pointerEvent.preventDefault();
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrap and relay a pointer event. Note that this requires that the type
|
||||
* string for the MapBrowserPointerEvent matches the PointerEvent type.
|
||||
* @param {module:ol/pointer/PointerEvent} pointerEvent Pointer
|
||||
* event.
|
||||
* @private
|
||||
*/
|
||||
relayEvent_(pointerEvent) {
|
||||
const dragging = !!(this.down_ && this.isMoving_(pointerEvent));
|
||||
this.dispatchEvent(new MapBrowserPointerEvent(
|
||||
pointerEvent.type, this.map_, pointerEvent, dragging));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {module:ol/pointer/PointerEvent} pointerEvent Pointer
|
||||
* event.
|
||||
* @return {boolean} Is moving.
|
||||
* @private
|
||||
*/
|
||||
isMoving_(pointerEvent) {
|
||||
return this.dragging_ ||
|
||||
Math.abs(pointerEvent.clientX - this.down_.clientX) > this.moveTolerance_ ||
|
||||
Math.abs(pointerEvent.clientY - this.down_.clientY) > this.moveTolerance_;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
disposeInternal() {
|
||||
if (this.relayedListenerKey_) {
|
||||
unlistenByKey(this.relayedListenerKey_);
|
||||
this.relayedListenerKey_ = null;
|
||||
}
|
||||
if (this.pointerdownListenerKey_) {
|
||||
unlistenByKey(this.pointerdownListenerKey_);
|
||||
this.pointerdownListenerKey_ = null;
|
||||
}
|
||||
|
||||
this.dragListenerKeys_.forEach(unlistenByKey);
|
||||
this.dragListenerKeys_.length = 0;
|
||||
this.dragging_ = false;
|
||||
this.down_ = null;
|
||||
this.documentPointerEventHandler_.dispose();
|
||||
this.documentPointerEventHandler_ = null;
|
||||
|
||||
if (this.documentPointerEventHandler_) {
|
||||
this.documentPointerEventHandler_.dispose();
|
||||
this.documentPointerEventHandler_ = null;
|
||||
}
|
||||
if (this.pointerEventHandler_) {
|
||||
this.pointerEventHandler_.dispose();
|
||||
this.pointerEventHandler_ = null;
|
||||
}
|
||||
super.disposeInternal();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param {module:ol/pointer/PointerEvent} pointerEvent Pointer
|
||||
* event.
|
||||
* @return {boolean} If the left mouse button was pressed.
|
||||
* @private
|
||||
*/
|
||||
MapBrowserEventHandler.prototype.isMouseActionButton_ = function(pointerEvent) {
|
||||
return pointerEvent.button === 0;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {module:ol/pointer/PointerEvent} pointerEvent Pointer
|
||||
* event.
|
||||
* @private
|
||||
*/
|
||||
MapBrowserEventHandler.prototype.handlePointerDown_ = function(pointerEvent) {
|
||||
this.updateActivePointers_(pointerEvent);
|
||||
const newEvent = new MapBrowserPointerEvent(
|
||||
MapBrowserEventType.POINTERDOWN, this.map_, pointerEvent);
|
||||
this.dispatchEvent(newEvent);
|
||||
|
||||
this.down_ = pointerEvent;
|
||||
|
||||
if (this.dragListenerKeys_.length === 0) {
|
||||
/* Set up a pointer event handler on the `document`,
|
||||
* which is required when the pointer is moved outside
|
||||
* the viewport when dragging.
|
||||
*/
|
||||
this.documentPointerEventHandler_ =
|
||||
new PointerEventHandler(document);
|
||||
|
||||
this.dragListenerKeys_.push(
|
||||
listen(this.documentPointerEventHandler_,
|
||||
MapBrowserEventType.POINTERMOVE,
|
||||
this.handlePointerMove_, this),
|
||||
listen(this.documentPointerEventHandler_,
|
||||
MapBrowserEventType.POINTERUP,
|
||||
this.handlePointerUp_, this),
|
||||
/* Note that the listener for `pointercancel is set up on
|
||||
* `pointerEventHandler_` and not `documentPointerEventHandler_` like
|
||||
* the `pointerup` and `pointermove` listeners.
|
||||
*
|
||||
* The reason for this is the following: `TouchSource.vacuumTouches_()`
|
||||
* issues `pointercancel` events, when there was no `touchend` for a
|
||||
* `touchstart`. Now, let's say a first `touchstart` is registered on
|
||||
* `pointerEventHandler_`. The `documentPointerEventHandler_` is set up.
|
||||
* But `documentPointerEventHandler_` doesn't know about the first
|
||||
* `touchstart`. If there is no `touchend` for the `touchstart`, we can
|
||||
* only receive a `touchcancel` from `pointerEventHandler_`, because it is
|
||||
* only registered there.
|
||||
*/
|
||||
listen(this.pointerEventHandler_,
|
||||
MapBrowserEventType.POINTERCANCEL,
|
||||
this.handlePointerUp_, this)
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {module:ol/pointer/PointerEvent} pointerEvent Pointer
|
||||
* event.
|
||||
* @private
|
||||
*/
|
||||
MapBrowserEventHandler.prototype.handlePointerMove_ = function(pointerEvent) {
|
||||
// Between pointerdown and pointerup, pointermove events are triggered.
|
||||
// To avoid a 'false' touchmove event to be dispatched, we test if the pointer
|
||||
// moved a significant distance.
|
||||
if (this.isMoving_(pointerEvent)) {
|
||||
this.dragging_ = true;
|
||||
const newEvent = new MapBrowserPointerEvent(
|
||||
MapBrowserEventType.POINTERDRAG, this.map_, pointerEvent,
|
||||
this.dragging_);
|
||||
this.dispatchEvent(newEvent);
|
||||
}
|
||||
|
||||
// Some native android browser triggers mousemove events during small period
|
||||
// of time. See: https://code.google.com/p/android/issues/detail?id=5491 or
|
||||
// https://code.google.com/p/android/issues/detail?id=19827
|
||||
// ex: Galaxy Tab P3110 + Android 4.1.1
|
||||
pointerEvent.preventDefault();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Wrap and relay a pointer event. Note that this requires that the type
|
||||
* string for the MapBrowserPointerEvent matches the PointerEvent type.
|
||||
* @param {module:ol/pointer/PointerEvent} pointerEvent Pointer
|
||||
* event.
|
||||
* @private
|
||||
*/
|
||||
MapBrowserEventHandler.prototype.relayEvent_ = function(pointerEvent) {
|
||||
const dragging = !!(this.down_ && this.isMoving_(pointerEvent));
|
||||
this.dispatchEvent(new MapBrowserPointerEvent(
|
||||
pointerEvent.type, this.map_, pointerEvent, dragging));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {module:ol/pointer/PointerEvent} pointerEvent Pointer
|
||||
* event.
|
||||
* @return {boolean} Is moving.
|
||||
* @private
|
||||
*/
|
||||
MapBrowserEventHandler.prototype.isMoving_ = function(pointerEvent) {
|
||||
return this.dragging_ ||
|
||||
Math.abs(pointerEvent.clientX - this.down_.clientX) > this.moveTolerance_ ||
|
||||
Math.abs(pointerEvent.clientY - this.down_.clientY) > this.moveTolerance_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
MapBrowserEventHandler.prototype.disposeInternal = function() {
|
||||
if (this.relayedListenerKey_) {
|
||||
unlistenByKey(this.relayedListenerKey_);
|
||||
this.relayedListenerKey_ = null;
|
||||
}
|
||||
if (this.pointerdownListenerKey_) {
|
||||
unlistenByKey(this.pointerdownListenerKey_);
|
||||
this.pointerdownListenerKey_ = null;
|
||||
}
|
||||
|
||||
this.dragListenerKeys_.forEach(unlistenByKey);
|
||||
this.dragListenerKeys_.length = 0;
|
||||
|
||||
if (this.documentPointerEventHandler_) {
|
||||
this.documentPointerEventHandler_.dispose();
|
||||
this.documentPointerEventHandler_ = null;
|
||||
}
|
||||
if (this.pointerEventHandler_) {
|
||||
this.pointerEventHandler_.dispose();
|
||||
this.pointerEventHandler_ = null;
|
||||
}
|
||||
EventTarget.prototype.disposeInternal.call(this);
|
||||
};
|
||||
export default MapBrowserEventHandler;
|
||||
|
||||
@@ -1,32 +1,29 @@
|
||||
/**
|
||||
* @module ol/MapBrowserPointerEvent
|
||||
*/
|
||||
import {inherits} from './util.js';
|
||||
import MapBrowserEvent from './MapBrowserEvent.js';
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
* @extends {module:ol/MapBrowserEvent}
|
||||
* @param {string} type Event type.
|
||||
* @param {module:ol/PluggableMap} map Map.
|
||||
* @param {module:ol/pointer/PointerEvent} pointerEvent Pointer
|
||||
* event.
|
||||
* @param {boolean=} opt_dragging Is the map currently being dragged?
|
||||
* @param {?module:ol/PluggableMap~FrameState=} opt_frameState Frame state.
|
||||
*/
|
||||
const MapBrowserPointerEvent = function(type, map, pointerEvent, opt_dragging,
|
||||
opt_frameState) {
|
||||
|
||||
MapBrowserEvent.call(this, type, map, pointerEvent.originalEvent, opt_dragging,
|
||||
opt_frameState);
|
||||
class MapBrowserPointerEvent extends MapBrowserEvent {
|
||||
|
||||
/**
|
||||
* @const
|
||||
* @type {module:ol/pointer/PointerEvent}
|
||||
* @param {string} type Event type.
|
||||
* @param {module:ol/PluggableMap} map Map.
|
||||
* @param {module:ol/pointer/PointerEvent} pointerEvent Pointer event.
|
||||
* @param {boolean=} opt_dragging Is the map currently being dragged?
|
||||
* @param {?module:ol/PluggableMap~FrameState=} opt_frameState Frame state.
|
||||
*/
|
||||
this.pointerEvent = pointerEvent;
|
||||
constructor(type, map, pointerEvent, opt_dragging, opt_frameState) {
|
||||
|
||||
};
|
||||
super(type, map, pointerEvent.originalEvent, opt_dragging, opt_frameState);
|
||||
|
||||
/**
|
||||
* @const
|
||||
* @type {module:ol/pointer/PointerEvent}
|
||||
*/
|
||||
this.pointerEvent = pointerEvent;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
inherits(MapBrowserPointerEvent, MapBrowserEvent);
|
||||
export default MapBrowserPointerEvent;
|
||||
|
||||
@@ -1,39 +1,40 @@
|
||||
/**
|
||||
* @module ol/MapEvent
|
||||
*/
|
||||
import {inherits} from './util.js';
|
||||
import Event from './events/Event.js';
|
||||
|
||||
/**
|
||||
* @classdesc
|
||||
* Events emitted as map events are instances of this type.
|
||||
* See {@link module:ol/Map~Map} for which events trigger a map event.
|
||||
*
|
||||
* @constructor
|
||||
* @extends {module:ol/events/Event}
|
||||
* @param {string} type Event type.
|
||||
* @param {module:ol/PluggableMap} map Map.
|
||||
* @param {?module:ol/PluggableMap~FrameState=} opt_frameState Frame state.
|
||||
*/
|
||||
const MapEvent = function(type, map, opt_frameState) {
|
||||
|
||||
Event.call(this, type);
|
||||
class MapEvent extends Event {
|
||||
|
||||
/**
|
||||
* The map where the event occurred.
|
||||
* @type {module:ol/PluggableMap}
|
||||
* @api
|
||||
* @param {string} type Event type.
|
||||
* @param {module:ol/PluggableMap} map Map.
|
||||
* @param {?module:ol/PluggableMap~FrameState=} opt_frameState Frame state.
|
||||
*/
|
||||
this.map = map;
|
||||
constructor(type, map, opt_frameState) {
|
||||
|
||||
/**
|
||||
* The frame state at the time of the event.
|
||||
* @type {?module:ol/PluggableMap~FrameState}
|
||||
* @api
|
||||
*/
|
||||
this.frameState = opt_frameState !== undefined ? opt_frameState : null;
|
||||
super(type);
|
||||
|
||||
};
|
||||
/**
|
||||
* The map where the event occurred.
|
||||
* @type {module:ol/PluggableMap}
|
||||
* @api
|
||||
*/
|
||||
this.map = map;
|
||||
|
||||
/**
|
||||
* The frame state at the time of the event.
|
||||
* @type {?module:ol/PluggableMap~FrameState}
|
||||
* @api
|
||||
*/
|
||||
this.frameState = opt_frameState !== undefined ? opt_frameState : null;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
inherits(MapEvent, Event);
|
||||
export default MapEvent;
|
||||
|
||||
279
src/ol/Object.js
279
src/ol/Object.js
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
* @module ol/Object
|
||||
*/
|
||||
import {getUid, inherits} from './util.js';
|
||||
import {getUid} from './util.js';
|
||||
import ObjectEventType from './ObjectEventType.js';
|
||||
import Observable from './Observable.js';
|
||||
import Event from './events/Event.js';
|
||||
@@ -10,35 +10,36 @@ import {assign} from './obj.js';
|
||||
|
||||
/**
|
||||
* @classdesc
|
||||
* Events emitted by {@link module:ol/Object~BaseObject} instances are instances of
|
||||
* this type.
|
||||
*
|
||||
* @param {string} type The event type.
|
||||
* @param {string} key The property name.
|
||||
* @param {*} oldValue The old value for `key`.
|
||||
* @extends {module:ol/events/Event}
|
||||
* @constructor
|
||||
*/
|
||||
const ObjectEvent = function(type, key, oldValue) {
|
||||
Event.call(this, type);
|
||||
* Events emitted by {@link module:ol/Object~BaseObject} instances are instances of this type.
|
||||
*/
|
||||
class ObjectEvent extends Event {
|
||||
|
||||
/**
|
||||
* The name of the property whose value is changing.
|
||||
* @type {string}
|
||||
* @api
|
||||
* @param {string} type The event type.
|
||||
* @param {string} key The property name.
|
||||
* @param {*} oldValue The old value for `key`.
|
||||
*/
|
||||
this.key = key;
|
||||
constructor(type, key, oldValue) {
|
||||
super(type);
|
||||
|
||||
/**
|
||||
* The old value. To get the new value use `e.target.get(e.key)` where
|
||||
* `e` is the event object.
|
||||
* @type {*}
|
||||
* @api
|
||||
*/
|
||||
this.oldValue = oldValue;
|
||||
/**
|
||||
* The name of the property whose value is changing.
|
||||
* @type {string}
|
||||
* @api
|
||||
*/
|
||||
this.key = key;
|
||||
|
||||
};
|
||||
inherits(ObjectEvent, Event);
|
||||
/**
|
||||
* The old value. To get the new value use `e.target.get(e.key)` where
|
||||
* `e` is the event object.
|
||||
* @type {*}
|
||||
* @api
|
||||
*/
|
||||
this.oldValue = oldValue;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
@@ -81,33 +82,126 @@ inherits(ObjectEvent, Event);
|
||||
* Properties can be deleted by using the unset method. E.g.
|
||||
* object.unset('foo').
|
||||
*
|
||||
* @constructor
|
||||
* @extends {module:ol/Observable}
|
||||
* @param {Object.<string, *>=} opt_values An object with key-value pairs.
|
||||
* @fires module:ol/Object~ObjectEvent
|
||||
* @api
|
||||
*/
|
||||
const BaseObject = function(opt_values) {
|
||||
Observable.call(this);
|
||||
|
||||
// Call {@link module:ol~getUid} to ensure that the order of objects' ids is
|
||||
// the same as the order in which they were created. This also helps to
|
||||
// ensure that object properties are always added in the same order, which
|
||||
// helps many JavaScript engines generate faster code.
|
||||
getUid(this);
|
||||
class BaseObject extends Observable {
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {!Object.<string, *>}
|
||||
* @param {Object.<string, *>=} opt_values An object with key-value pairs.
|
||||
*/
|
||||
this.values_ = {};
|
||||
constructor(opt_values) {
|
||||
super();
|
||||
|
||||
if (opt_values !== undefined) {
|
||||
this.setProperties(opt_values);
|
||||
// Call {@link module:ol~getUid} to ensure that the order of objects' ids is
|
||||
// the same as the order in which they were created. This also helps to
|
||||
// ensure that object properties are always added in the same order, which
|
||||
// helps many JavaScript engines generate faster code.
|
||||
getUid(this);
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {!Object.<string, *>}
|
||||
*/
|
||||
this.values_ = {};
|
||||
|
||||
if (opt_values !== undefined) {
|
||||
this.setProperties(opt_values);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
inherits(BaseObject, Observable);
|
||||
/**
|
||||
* Gets a value.
|
||||
* @param {string} key Key name.
|
||||
* @return {*} Value.
|
||||
* @api
|
||||
*/
|
||||
get(key) {
|
||||
let value;
|
||||
if (this.values_.hasOwnProperty(key)) {
|
||||
value = this.values_[key];
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of object property names.
|
||||
* @return {Array.<string>} List of property names.
|
||||
* @api
|
||||
*/
|
||||
getKeys() {
|
||||
return Object.keys(this.values_);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an object of all property names and values.
|
||||
* @return {Object.<string, *>} Object.
|
||||
* @api
|
||||
*/
|
||||
getProperties() {
|
||||
return assign({}, this.values_);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} key Key name.
|
||||
* @param {*} oldValue Old value.
|
||||
*/
|
||||
notify(key, oldValue) {
|
||||
let eventType;
|
||||
eventType = getChangeEventType(key);
|
||||
this.dispatchEvent(new ObjectEvent(eventType, key, oldValue));
|
||||
eventType = ObjectEventType.PROPERTYCHANGE;
|
||||
this.dispatchEvent(new ObjectEvent(eventType, key, oldValue));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a value.
|
||||
* @param {string} key Key name.
|
||||
* @param {*} value Value.
|
||||
* @param {boolean=} opt_silent Update without triggering an event.
|
||||
* @api
|
||||
*/
|
||||
set(key, value, opt_silent) {
|
||||
if (opt_silent) {
|
||||
this.values_[key] = value;
|
||||
} else {
|
||||
const oldValue = this.values_[key];
|
||||
this.values_[key] = value;
|
||||
if (oldValue !== value) {
|
||||
this.notify(key, oldValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a collection of key-value pairs. Note that this changes any existing
|
||||
* properties and adds new ones (it does not remove any existing properties).
|
||||
* @param {Object.<string, *>} values Values.
|
||||
* @param {boolean=} opt_silent Update without triggering an event.
|
||||
* @api
|
||||
*/
|
||||
setProperties(values, opt_silent) {
|
||||
for (const key in values) {
|
||||
this.set(key, values[key], opt_silent);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unsets a property.
|
||||
* @param {string} key Key name.
|
||||
* @param {boolean=} opt_silent Unset without triggering an event.
|
||||
* @api
|
||||
*/
|
||||
unset(key, opt_silent) {
|
||||
if (key in this.values_) {
|
||||
const oldValue = this.values_[key];
|
||||
delete this.values_[key];
|
||||
if (!opt_silent) {
|
||||
this.notify(key, oldValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
@@ -127,103 +221,4 @@ export function getChangeEventType(key) {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets a value.
|
||||
* @param {string} key Key name.
|
||||
* @return {*} Value.
|
||||
* @api
|
||||
*/
|
||||
BaseObject.prototype.get = function(key) {
|
||||
let value;
|
||||
if (this.values_.hasOwnProperty(key)) {
|
||||
value = this.values_[key];
|
||||
}
|
||||
return value;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get a list of object property names.
|
||||
* @return {Array.<string>} List of property names.
|
||||
* @api
|
||||
*/
|
||||
BaseObject.prototype.getKeys = function() {
|
||||
return Object.keys(this.values_);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get an object of all property names and values.
|
||||
* @return {Object.<string, *>} Object.
|
||||
* @api
|
||||
*/
|
||||
BaseObject.prototype.getProperties = function() {
|
||||
return assign({}, this.values_);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {string} key Key name.
|
||||
* @param {*} oldValue Old value.
|
||||
*/
|
||||
BaseObject.prototype.notify = function(key, oldValue) {
|
||||
let eventType;
|
||||
eventType = getChangeEventType(key);
|
||||
this.dispatchEvent(new ObjectEvent(eventType, key, oldValue));
|
||||
eventType = ObjectEventType.PROPERTYCHANGE;
|
||||
this.dispatchEvent(new ObjectEvent(eventType, key, oldValue));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Sets a value.
|
||||
* @param {string} key Key name.
|
||||
* @param {*} value Value.
|
||||
* @param {boolean=} opt_silent Update without triggering an event.
|
||||
* @api
|
||||
*/
|
||||
BaseObject.prototype.set = function(key, value, opt_silent) {
|
||||
if (opt_silent) {
|
||||
this.values_[key] = value;
|
||||
} else {
|
||||
const oldValue = this.values_[key];
|
||||
this.values_[key] = value;
|
||||
if (oldValue !== value) {
|
||||
this.notify(key, oldValue);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Sets a collection of key-value pairs. Note that this changes any existing
|
||||
* properties and adds new ones (it does not remove any existing properties).
|
||||
* @param {Object.<string, *>} values Values.
|
||||
* @param {boolean=} opt_silent Update without triggering an event.
|
||||
* @api
|
||||
*/
|
||||
BaseObject.prototype.setProperties = function(values, opt_silent) {
|
||||
for (const key in values) {
|
||||
this.set(key, values[key], opt_silent);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Unsets a property.
|
||||
* @param {string} key Key name.
|
||||
* @param {boolean=} opt_silent Unset without triggering an event.
|
||||
* @api
|
||||
*/
|
||||
BaseObject.prototype.unset = function(key, opt_silent) {
|
||||
if (key in this.values_) {
|
||||
const oldValue = this.values_[key];
|
||||
delete this.values_[key];
|
||||
if (!opt_silent) {
|
||||
this.notify(key, oldValue);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
export default BaseObject;
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
/**
|
||||
* @module ol/Observable
|
||||
*/
|
||||
import {inherits} from './util.js';
|
||||
import {listen, unlistenByKey, unlisten, listenOnce} from './events.js';
|
||||
import EventTarget from './events/EventTarget.js';
|
||||
import EventType from './events/EventType.js';
|
||||
@@ -14,25 +13,102 @@ import EventType from './events/EventType.js';
|
||||
* and unregistration. A generic `change` event is always available through
|
||||
* {@link module:ol/Observable~Observable#changed}.
|
||||
*
|
||||
* @constructor
|
||||
* @extends {module:ol/events/EventTarget}
|
||||
* @fires module:ol/events/Event~Event
|
||||
* @struct
|
||||
* @api
|
||||
*/
|
||||
const Observable = function() {
|
||||
class Observable extends EventTarget {
|
||||
constructor() {
|
||||
|
||||
EventTarget.call(this);
|
||||
super();
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {number}
|
||||
*/
|
||||
this.revision_ = 0;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {number}
|
||||
* Increases the revision counter and dispatches a 'change' event.
|
||||
* @api
|
||||
*/
|
||||
this.revision_ = 0;
|
||||
changed() {
|
||||
++this.revision_;
|
||||
this.dispatchEvent(EventType.CHANGE);
|
||||
}
|
||||
|
||||
};
|
||||
/**
|
||||
* Get the version number for this object. Each time the object is modified,
|
||||
* its version number will be incremented.
|
||||
* @return {number} Revision.
|
||||
* @api
|
||||
*/
|
||||
getRevision() {
|
||||
return this.revision_;
|
||||
}
|
||||
|
||||
inherits(Observable, EventTarget);
|
||||
/**
|
||||
* Listen for a certain type of event.
|
||||
* @param {string|Array.<string>} type The event type or array of event types.
|
||||
* @param {function(?): ?} listener The listener function.
|
||||
* @return {module:ol/events~EventsKey|Array.<module:ol/events~EventsKey>} Unique key for the listener. If
|
||||
* called with an array of event types as the first argument, the return
|
||||
* will be an array of keys.
|
||||
* @api
|
||||
*/
|
||||
on(type, listener) {
|
||||
if (Array.isArray(type)) {
|
||||
const len = type.length;
|
||||
const keys = new Array(len);
|
||||
for (let i = 0; i < len; ++i) {
|
||||
keys[i] = listen(this, type[i], listener);
|
||||
}
|
||||
return keys;
|
||||
} else {
|
||||
return listen(this, /** @type {string} */ (type), listener);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Listen once for a certain type of event.
|
||||
* @param {string|Array.<string>} type The event type or array of event types.
|
||||
* @param {function(?): ?} listener The listener function.
|
||||
* @return {module:ol/events~EventsKey|Array.<module:ol/events~EventsKey>} Unique key for the listener. If
|
||||
* called with an array of event types as the first argument, the return
|
||||
* will be an array of keys.
|
||||
* @api
|
||||
*/
|
||||
once(type, listener) {
|
||||
if (Array.isArray(type)) {
|
||||
const len = type.length;
|
||||
const keys = new Array(len);
|
||||
for (let i = 0; i < len; ++i) {
|
||||
keys[i] = listenOnce(this, type[i], listener);
|
||||
}
|
||||
return keys;
|
||||
} else {
|
||||
return listenOnce(this, /** @type {string} */ (type), listener);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unlisten for a certain type of event.
|
||||
* @param {string|Array.<string>} type The event type or array of event types.
|
||||
* @param {function(?): ?} listener The listener function.
|
||||
* @api
|
||||
*/
|
||||
un(type, listener) {
|
||||
if (Array.isArray(type)) {
|
||||
for (let i = 0, ii = type.length; i < ii; ++i) {
|
||||
unlisten(this, type[i], listener);
|
||||
}
|
||||
return;
|
||||
} else {
|
||||
unlisten(this, /** @type {string} */ (type), listener);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
@@ -52,101 +128,4 @@ export function unByKey(key) {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Increases the revision counter and dispatches a 'change' event.
|
||||
* @api
|
||||
*/
|
||||
Observable.prototype.changed = function() {
|
||||
++this.revision_;
|
||||
this.dispatchEvent(EventType.CHANGE);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Dispatches an event and calls all listeners listening for events
|
||||
* of this type. The event parameter can either be a string or an
|
||||
* Object with a `type` property.
|
||||
*
|
||||
* @param {{type: string,
|
||||
* target: (EventTarget|module:ol/events/EventTarget|undefined)}|
|
||||
* module:ol/events/Event|string} event Event object.
|
||||
* @function
|
||||
* @api
|
||||
*/
|
||||
Observable.prototype.dispatchEvent;
|
||||
|
||||
|
||||
/**
|
||||
* Get the version number for this object. Each time the object is modified,
|
||||
* its version number will be incremented.
|
||||
* @return {number} Revision.
|
||||
* @api
|
||||
*/
|
||||
Observable.prototype.getRevision = function() {
|
||||
return this.revision_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Listen for a certain type of event.
|
||||
* @param {string|Array.<string>} type The event type or array of event types.
|
||||
* @param {function(?): ?} listener The listener function.
|
||||
* @return {module:ol/events~EventsKey|Array.<module:ol/events~EventsKey>} Unique key for the listener. If
|
||||
* called with an array of event types as the first argument, the return
|
||||
* will be an array of keys.
|
||||
* @api
|
||||
*/
|
||||
Observable.prototype.on = function(type, listener) {
|
||||
if (Array.isArray(type)) {
|
||||
const len = type.length;
|
||||
const keys = new Array(len);
|
||||
for (let i = 0; i < len; ++i) {
|
||||
keys[i] = listen(this, type[i], listener);
|
||||
}
|
||||
return keys;
|
||||
} else {
|
||||
return listen(this, /** @type {string} */ (type), listener);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Listen once for a certain type of event.
|
||||
* @param {string|Array.<string>} type The event type or array of event types.
|
||||
* @param {function(?): ?} listener The listener function.
|
||||
* @return {module:ol/events~EventsKey|Array.<module:ol/events~EventsKey>} Unique key for the listener. If
|
||||
* called with an array of event types as the first argument, the return
|
||||
* will be an array of keys.
|
||||
* @api
|
||||
*/
|
||||
Observable.prototype.once = function(type, listener) {
|
||||
if (Array.isArray(type)) {
|
||||
const len = type.length;
|
||||
const keys = new Array(len);
|
||||
for (let i = 0; i < len; ++i) {
|
||||
keys[i] = listenOnce(this, type[i], listener);
|
||||
}
|
||||
return keys;
|
||||
} else {
|
||||
return listenOnce(this, /** @type {string} */ (type), listener);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Unlisten for a certain type of event.
|
||||
* @param {string|Array.<string>} type The event type or array of event types.
|
||||
* @param {function(?): ?} listener The listener function.
|
||||
* @api
|
||||
*/
|
||||
Observable.prototype.un = function(type, listener) {
|
||||
if (Array.isArray(type)) {
|
||||
for (let i = 0, ii = type.length; i < ii; ++i) {
|
||||
unlisten(this, type[i], listener);
|
||||
}
|
||||
return;
|
||||
} else {
|
||||
unlisten(this, /** @type {string} */ (type), listener);
|
||||
}
|
||||
};
|
||||
export default Observable;
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
/**
|
||||
* @module ol/Overlay
|
||||
*/
|
||||
import {inherits} from './util.js';
|
||||
import MapEventType from './MapEventType.js';
|
||||
import BaseObject, {getChangeEventType} from './Object.js';
|
||||
import OverlayPositioning from './OverlayPositioning.js';
|
||||
@@ -93,515 +92,494 @@ const Property = {
|
||||
* popup.setPosition(coordinate);
|
||||
* map.addOverlay(popup);
|
||||
*
|
||||
* @constructor
|
||||
* @extends {module:ol/Object}
|
||||
* @param {module:ol/Overlay~Options} options Overlay options.
|
||||
* @api
|
||||
*/
|
||||
const Overlay = function(options) {
|
||||
|
||||
BaseObject.call(this);
|
||||
class Overlay extends BaseObject {
|
||||
|
||||
/**
|
||||
* @protected
|
||||
* @type {module:ol/Overlay~Options}
|
||||
* @param {module:ol/Overlay~Options} options Overlay options.
|
||||
*/
|
||||
this.options = options;
|
||||
constructor(options) {
|
||||
|
||||
/**
|
||||
* @protected
|
||||
* @type {number|string|undefined}
|
||||
*/
|
||||
this.id = options.id;
|
||||
super();
|
||||
|
||||
/**
|
||||
* @protected
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.insertFirst = options.insertFirst !== undefined ?
|
||||
options.insertFirst : true;
|
||||
/**
|
||||
* @protected
|
||||
* @type {module:ol/Overlay~Options}
|
||||
*/
|
||||
this.options = options;
|
||||
|
||||
/**
|
||||
* @protected
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.stopEvent = options.stopEvent !== undefined ? options.stopEvent : true;
|
||||
/**
|
||||
* @protected
|
||||
* @type {number|string|undefined}
|
||||
*/
|
||||
this.id = options.id;
|
||||
|
||||
/**
|
||||
* @protected
|
||||
* @type {HTMLElement}
|
||||
*/
|
||||
this.element = document.createElement('DIV');
|
||||
this.element.className = options.className !== undefined ?
|
||||
options.className : 'ol-overlay-container ' + CLASS_SELECTABLE;
|
||||
this.element.style.position = 'absolute';
|
||||
/**
|
||||
* @protected
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.insertFirst = options.insertFirst !== undefined ?
|
||||
options.insertFirst : true;
|
||||
|
||||
/**
|
||||
* @protected
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.autoPan = options.autoPan !== undefined ? options.autoPan : false;
|
||||
/**
|
||||
* @protected
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.stopEvent = options.stopEvent !== undefined ? options.stopEvent : true;
|
||||
|
||||
/**
|
||||
* @protected
|
||||
* @type {module:ol/Overlay~PanOptions}
|
||||
*/
|
||||
this.autoPanAnimation = options.autoPanAnimation || /** @type {module:ol/Overlay~PanOptions} */ ({});
|
||||
/**
|
||||
* @protected
|
||||
* @type {HTMLElement}
|
||||
*/
|
||||
this.element = document.createElement('DIV');
|
||||
this.element.className = options.className !== undefined ?
|
||||
options.className : 'ol-overlay-container ' + CLASS_SELECTABLE;
|
||||
this.element.style.position = 'absolute';
|
||||
|
||||
/**
|
||||
* @protected
|
||||
* @type {number}
|
||||
*/
|
||||
this.autoPanMargin = options.autoPanMargin !== undefined ?
|
||||
options.autoPanMargin : 20;
|
||||
/**
|
||||
* @protected
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.autoPan = options.autoPan !== undefined ? options.autoPan : false;
|
||||
|
||||
/**
|
||||
* @protected
|
||||
* @type {{bottom_: string,
|
||||
* left_: string,
|
||||
* right_: string,
|
||||
* top_: string,
|
||||
* visible: boolean}}
|
||||
*/
|
||||
this.rendered = {
|
||||
bottom_: '',
|
||||
left_: '',
|
||||
right_: '',
|
||||
top_: '',
|
||||
visible: true
|
||||
};
|
||||
/**
|
||||
* @protected
|
||||
* @type {module:ol/Overlay~PanOptions}
|
||||
*/
|
||||
this.autoPanAnimation = options.autoPanAnimation || /** @type {module:ol/Overlay~PanOptions} */ ({});
|
||||
|
||||
/**
|
||||
* @protected
|
||||
* @type {?module:ol/events~EventsKey}
|
||||
*/
|
||||
this.mapPostrenderListenerKey = null;
|
||||
/**
|
||||
* @protected
|
||||
* @type {number}
|
||||
*/
|
||||
this.autoPanMargin = options.autoPanMargin !== undefined ?
|
||||
options.autoPanMargin : 20;
|
||||
|
||||
listen(
|
||||
this, getChangeEventType(Property.ELEMENT),
|
||||
this.handleElementChanged, this);
|
||||
/**
|
||||
* @protected
|
||||
* @type {{bottom_: string,
|
||||
* left_: string,
|
||||
* right_: string,
|
||||
* top_: string,
|
||||
* visible: boolean}}
|
||||
*/
|
||||
this.rendered = {
|
||||
bottom_: '',
|
||||
left_: '',
|
||||
right_: '',
|
||||
top_: '',
|
||||
visible: true
|
||||
};
|
||||
|
||||
listen(
|
||||
this, getChangeEventType(Property.MAP),
|
||||
this.handleMapChanged, this);
|
||||
|
||||
listen(
|
||||
this, getChangeEventType(Property.OFFSET),
|
||||
this.handleOffsetChanged, this);
|
||||
|
||||
listen(
|
||||
this, getChangeEventType(Property.POSITION),
|
||||
this.handlePositionChanged, this);
|
||||
|
||||
listen(
|
||||
this, getChangeEventType(Property.POSITIONING),
|
||||
this.handlePositioningChanged, this);
|
||||
|
||||
if (options.element !== undefined) {
|
||||
this.setElement(options.element);
|
||||
}
|
||||
|
||||
this.setOffset(options.offset !== undefined ? options.offset : [0, 0]);
|
||||
|
||||
this.setPositioning(options.positioning !== undefined ?
|
||||
/** @type {module:ol/OverlayPositioning} */ (options.positioning) :
|
||||
OverlayPositioning.TOP_LEFT);
|
||||
|
||||
if (options.position !== undefined) {
|
||||
this.setPosition(options.position);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
inherits(Overlay, BaseObject);
|
||||
|
||||
|
||||
/**
|
||||
* Get the DOM element of this overlay.
|
||||
* @return {HTMLElement|undefined} The Element containing the overlay.
|
||||
* @observable
|
||||
* @api
|
||||
*/
|
||||
Overlay.prototype.getElement = function() {
|
||||
return /** @type {HTMLElement|undefined} */ (this.get(Property.ELEMENT));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get the overlay identifier which is set on constructor.
|
||||
* @return {number|string|undefined} Id.
|
||||
* @api
|
||||
*/
|
||||
Overlay.prototype.getId = function() {
|
||||
return this.id;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get the map associated with this overlay.
|
||||
* @return {module:ol/PluggableMap|undefined} The map that the
|
||||
* overlay is part of.
|
||||
* @observable
|
||||
* @api
|
||||
*/
|
||||
Overlay.prototype.getMap = function() {
|
||||
return (
|
||||
/** @type {module:ol/PluggableMap|undefined} */ (this.get(Property.MAP))
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get the offset of this overlay.
|
||||
* @return {Array.<number>} The offset.
|
||||
* @observable
|
||||
* @api
|
||||
*/
|
||||
Overlay.prototype.getOffset = function() {
|
||||
return /** @type {Array.<number>} */ (this.get(Property.OFFSET));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get the current position of this overlay.
|
||||
* @return {module:ol/coordinate~Coordinate|undefined} The spatial point that the overlay is
|
||||
* anchored at.
|
||||
* @observable
|
||||
* @api
|
||||
*/
|
||||
Overlay.prototype.getPosition = function() {
|
||||
return (
|
||||
/** @type {module:ol/coordinate~Coordinate|undefined} */ (this.get(Property.POSITION))
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get the current positioning of this overlay.
|
||||
* @return {module:ol/OverlayPositioning} How the overlay is positioned
|
||||
* relative to its point on the map.
|
||||
* @observable
|
||||
* @api
|
||||
*/
|
||||
Overlay.prototype.getPositioning = function() {
|
||||
return (
|
||||
/** @type {module:ol/OverlayPositioning} */ (this.get(Property.POSITIONING))
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @protected
|
||||
*/
|
||||
Overlay.prototype.handleElementChanged = function() {
|
||||
removeChildren(this.element);
|
||||
const element = this.getElement();
|
||||
if (element) {
|
||||
this.element.appendChild(element);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @protected
|
||||
*/
|
||||
Overlay.prototype.handleMapChanged = function() {
|
||||
if (this.mapPostrenderListenerKey) {
|
||||
removeNode(this.element);
|
||||
unlistenByKey(this.mapPostrenderListenerKey);
|
||||
/**
|
||||
* @protected
|
||||
* @type {?module:ol/events~EventsKey}
|
||||
*/
|
||||
this.mapPostrenderListenerKey = null;
|
||||
|
||||
listen(
|
||||
this, getChangeEventType(Property.ELEMENT),
|
||||
this.handleElementChanged, this);
|
||||
|
||||
listen(
|
||||
this, getChangeEventType(Property.MAP),
|
||||
this.handleMapChanged, this);
|
||||
|
||||
listen(
|
||||
this, getChangeEventType(Property.OFFSET),
|
||||
this.handleOffsetChanged, this);
|
||||
|
||||
listen(
|
||||
this, getChangeEventType(Property.POSITION),
|
||||
this.handlePositionChanged, this);
|
||||
|
||||
listen(
|
||||
this, getChangeEventType(Property.POSITIONING),
|
||||
this.handlePositioningChanged, this);
|
||||
|
||||
if (options.element !== undefined) {
|
||||
this.setElement(options.element);
|
||||
}
|
||||
|
||||
this.setOffset(options.offset !== undefined ? options.offset : [0, 0]);
|
||||
|
||||
this.setPositioning(options.positioning !== undefined ?
|
||||
/** @type {module:ol/OverlayPositioning} */ (options.positioning) :
|
||||
OverlayPositioning.TOP_LEFT);
|
||||
|
||||
if (options.position !== undefined) {
|
||||
this.setPosition(options.position);
|
||||
}
|
||||
|
||||
}
|
||||
const map = this.getMap();
|
||||
if (map) {
|
||||
this.mapPostrenderListenerKey = listen(map,
|
||||
MapEventType.POSTRENDER, this.render, this);
|
||||
|
||||
/**
|
||||
* Get the DOM element of this overlay.
|
||||
* @return {HTMLElement|undefined} The Element containing the overlay.
|
||||
* @observable
|
||||
* @api
|
||||
*/
|
||||
getElement() {
|
||||
return /** @type {HTMLElement|undefined} */ (this.get(Property.ELEMENT));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the overlay identifier which is set on constructor.
|
||||
* @return {number|string|undefined} Id.
|
||||
* @api
|
||||
*/
|
||||
getId() {
|
||||
return this.id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the map associated with this overlay.
|
||||
* @return {module:ol/PluggableMap|undefined} The map that the
|
||||
* overlay is part of.
|
||||
* @observable
|
||||
* @api
|
||||
*/
|
||||
getMap() {
|
||||
return (
|
||||
/** @type {module:ol/PluggableMap|undefined} */ (this.get(Property.MAP))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the offset of this overlay.
|
||||
* @return {Array.<number>} The offset.
|
||||
* @observable
|
||||
* @api
|
||||
*/
|
||||
getOffset() {
|
||||
return /** @type {Array.<number>} */ (this.get(Property.OFFSET));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current position of this overlay.
|
||||
* @return {module:ol/coordinate~Coordinate|undefined} The spatial point that the overlay is
|
||||
* anchored at.
|
||||
* @observable
|
||||
* @api
|
||||
*/
|
||||
getPosition() {
|
||||
return (
|
||||
/** @type {module:ol/coordinate~Coordinate|undefined} */ (this.get(Property.POSITION))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current positioning of this overlay.
|
||||
* @return {module:ol/OverlayPositioning} How the overlay is positioned
|
||||
* relative to its point on the map.
|
||||
* @observable
|
||||
* @api
|
||||
*/
|
||||
getPositioning() {
|
||||
return (
|
||||
/** @type {module:ol/OverlayPositioning} */ (this.get(Property.POSITIONING))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @protected
|
||||
*/
|
||||
handleElementChanged() {
|
||||
removeChildren(this.element);
|
||||
const element = this.getElement();
|
||||
if (element) {
|
||||
this.element.appendChild(element);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @protected
|
||||
*/
|
||||
handleMapChanged() {
|
||||
if (this.mapPostrenderListenerKey) {
|
||||
removeNode(this.element);
|
||||
unlistenByKey(this.mapPostrenderListenerKey);
|
||||
this.mapPostrenderListenerKey = null;
|
||||
}
|
||||
const map = this.getMap();
|
||||
if (map) {
|
||||
this.mapPostrenderListenerKey = listen(map,
|
||||
MapEventType.POSTRENDER, this.render, this);
|
||||
this.updatePixelPosition();
|
||||
const container = this.stopEvent ?
|
||||
map.getOverlayContainerStopEvent() : map.getOverlayContainer();
|
||||
if (this.insertFirst) {
|
||||
container.insertBefore(this.element, container.childNodes[0] || null);
|
||||
} else {
|
||||
container.appendChild(this.element);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @protected
|
||||
*/
|
||||
render() {
|
||||
this.updatePixelPosition();
|
||||
const container = this.stopEvent ?
|
||||
map.getOverlayContainerStopEvent() : map.getOverlayContainer();
|
||||
if (this.insertFirst) {
|
||||
container.insertBefore(this.element, container.childNodes[0] || null);
|
||||
}
|
||||
|
||||
/**
|
||||
* @protected
|
||||
*/
|
||||
handleOffsetChanged() {
|
||||
this.updatePixelPosition();
|
||||
}
|
||||
|
||||
/**
|
||||
* @protected
|
||||
*/
|
||||
handlePositionChanged() {
|
||||
this.updatePixelPosition();
|
||||
if (this.get(Property.POSITION) && this.autoPan) {
|
||||
this.panIntoView();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @protected
|
||||
*/
|
||||
handlePositioningChanged() {
|
||||
this.updatePixelPosition();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the DOM element to be associated with this overlay.
|
||||
* @param {HTMLElement|undefined} element The Element containing the overlay.
|
||||
* @observable
|
||||
* @api
|
||||
*/
|
||||
setElement(element) {
|
||||
this.set(Property.ELEMENT, element);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the map to be associated with this overlay.
|
||||
* @param {module:ol/PluggableMap|undefined} map The map that the
|
||||
* overlay is part of.
|
||||
* @observable
|
||||
* @api
|
||||
*/
|
||||
setMap(map) {
|
||||
this.set(Property.MAP, map);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the offset for this overlay.
|
||||
* @param {Array.<number>} offset Offset.
|
||||
* @observable
|
||||
* @api
|
||||
*/
|
||||
setOffset(offset) {
|
||||
this.set(Property.OFFSET, offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the position for this overlay. If the position is `undefined` the
|
||||
* overlay is hidden.
|
||||
* @param {module:ol/coordinate~Coordinate|undefined} position The spatial point that the overlay
|
||||
* is anchored at.
|
||||
* @observable
|
||||
* @api
|
||||
*/
|
||||
setPosition(position) {
|
||||
this.set(Property.POSITION, position);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pan the map so that the overlay is entirely visible in the current viewport
|
||||
* (if necessary).
|
||||
* @protected
|
||||
*/
|
||||
panIntoView() {
|
||||
const map = this.getMap();
|
||||
|
||||
if (!map || !map.getTargetElement()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const mapRect = this.getRect(map.getTargetElement(), map.getSize());
|
||||
const element = this.getElement();
|
||||
const overlayRect = this.getRect(element, [outerWidth(element), outerHeight(element)]);
|
||||
|
||||
const margin = this.autoPanMargin;
|
||||
if (!containsExtent(mapRect, overlayRect)) {
|
||||
// the overlay is not completely inside the viewport, so pan the map
|
||||
const offsetLeft = overlayRect[0] - mapRect[0];
|
||||
const offsetRight = mapRect[2] - overlayRect[2];
|
||||
const offsetTop = overlayRect[1] - mapRect[1];
|
||||
const offsetBottom = mapRect[3] - overlayRect[3];
|
||||
|
||||
const delta = [0, 0];
|
||||
if (offsetLeft < 0) {
|
||||
// move map to the left
|
||||
delta[0] = offsetLeft - margin;
|
||||
} else if (offsetRight < 0) {
|
||||
// move map to the right
|
||||
delta[0] = Math.abs(offsetRight) + margin;
|
||||
}
|
||||
if (offsetTop < 0) {
|
||||
// move map up
|
||||
delta[1] = offsetTop - margin;
|
||||
} else if (offsetBottom < 0) {
|
||||
// move map down
|
||||
delta[1] = Math.abs(offsetBottom) + margin;
|
||||
}
|
||||
|
||||
if (delta[0] !== 0 || delta[1] !== 0) {
|
||||
const center = /** @type {module:ol/coordinate~Coordinate} */ (map.getView().getCenter());
|
||||
const centerPx = map.getPixelFromCoordinate(center);
|
||||
const newCenterPx = [
|
||||
centerPx[0] + delta[0],
|
||||
centerPx[1] + delta[1]
|
||||
];
|
||||
|
||||
map.getView().animate({
|
||||
center: map.getCoordinateFromPixel(newCenterPx),
|
||||
duration: this.autoPanAnimation.duration,
|
||||
easing: this.autoPanAnimation.easing
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the extent of an element relative to the document
|
||||
* @param {HTMLElement|undefined} element The element.
|
||||
* @param {module:ol/size~Size|undefined} size The size of the element.
|
||||
* @return {module:ol/extent~Extent} The extent.
|
||||
* @protected
|
||||
*/
|
||||
getRect(element, size) {
|
||||
const box = element.getBoundingClientRect();
|
||||
const offsetX = box.left + window.pageXOffset;
|
||||
const offsetY = box.top + window.pageYOffset;
|
||||
return [
|
||||
offsetX,
|
||||
offsetY,
|
||||
offsetX + size[0],
|
||||
offsetY + size[1]
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the positioning for this overlay.
|
||||
* @param {module:ol/OverlayPositioning} positioning how the overlay is
|
||||
* positioned relative to its point on the map.
|
||||
* @observable
|
||||
* @api
|
||||
*/
|
||||
setPositioning(positioning) {
|
||||
this.set(Property.POSITIONING, positioning);
|
||||
}
|
||||
|
||||
/**
|
||||
* Modify the visibility of the element.
|
||||
* @param {boolean} visible Element visibility.
|
||||
* @protected
|
||||
*/
|
||||
setVisible(visible) {
|
||||
if (this.rendered.visible !== visible) {
|
||||
this.element.style.display = visible ? '' : 'none';
|
||||
this.rendered.visible = visible;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update pixel position.
|
||||
* @protected
|
||||
*/
|
||||
updatePixelPosition() {
|
||||
const map = this.getMap();
|
||||
const position = this.getPosition();
|
||||
if (!map || !map.isRendered() || !position) {
|
||||
this.setVisible(false);
|
||||
return;
|
||||
}
|
||||
|
||||
const pixel = map.getPixelFromCoordinate(position);
|
||||
const mapSize = map.getSize();
|
||||
this.updateRenderedPosition(pixel, mapSize);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {module:ol~Pixel} pixel The pixel location.
|
||||
* @param {module:ol/size~Size|undefined} mapSize The map size.
|
||||
* @protected
|
||||
*/
|
||||
updateRenderedPosition(pixel, mapSize) {
|
||||
const style = this.element.style;
|
||||
const offset = this.getOffset();
|
||||
|
||||
const positioning = this.getPositioning();
|
||||
|
||||
this.setVisible(true);
|
||||
|
||||
let offsetX = offset[0];
|
||||
let offsetY = offset[1];
|
||||
if (positioning == OverlayPositioning.BOTTOM_RIGHT ||
|
||||
positioning == OverlayPositioning.CENTER_RIGHT ||
|
||||
positioning == OverlayPositioning.TOP_RIGHT) {
|
||||
if (this.rendered.left_ !== '') {
|
||||
this.rendered.left_ = style.left = '';
|
||||
}
|
||||
const right = Math.round(mapSize[0] - pixel[0] - offsetX) + 'px';
|
||||
if (this.rendered.right_ != right) {
|
||||
this.rendered.right_ = style.right = right;
|
||||
}
|
||||
} else {
|
||||
container.appendChild(this.element);
|
||||
if (this.rendered.right_ !== '') {
|
||||
this.rendered.right_ = style.right = '';
|
||||
}
|
||||
if (positioning == OverlayPositioning.BOTTOM_CENTER ||
|
||||
positioning == OverlayPositioning.CENTER_CENTER ||
|
||||
positioning == OverlayPositioning.TOP_CENTER) {
|
||||
offsetX -= this.element.offsetWidth / 2;
|
||||
}
|
||||
const left = Math.round(pixel[0] + offsetX) + 'px';
|
||||
if (this.rendered.left_ != left) {
|
||||
this.rendered.left_ = style.left = left;
|
||||
}
|
||||
}
|
||||
if (positioning == OverlayPositioning.BOTTOM_LEFT ||
|
||||
positioning == OverlayPositioning.BOTTOM_CENTER ||
|
||||
positioning == OverlayPositioning.BOTTOM_RIGHT) {
|
||||
if (this.rendered.top_ !== '') {
|
||||
this.rendered.top_ = style.top = '';
|
||||
}
|
||||
const bottom = Math.round(mapSize[1] - pixel[1] - offsetY) + 'px';
|
||||
if (this.rendered.bottom_ != bottom) {
|
||||
this.rendered.bottom_ = style.bottom = bottom;
|
||||
}
|
||||
} else {
|
||||
if (this.rendered.bottom_ !== '') {
|
||||
this.rendered.bottom_ = style.bottom = '';
|
||||
}
|
||||
if (positioning == OverlayPositioning.CENTER_LEFT ||
|
||||
positioning == OverlayPositioning.CENTER_CENTER ||
|
||||
positioning == OverlayPositioning.CENTER_RIGHT) {
|
||||
offsetY -= this.element.offsetHeight / 2;
|
||||
}
|
||||
const top = Math.round(pixel[1] + offsetY) + 'px';
|
||||
if (this.rendered.top_ != top) {
|
||||
this.rendered.top_ = style.top = top;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @protected
|
||||
*/
|
||||
Overlay.prototype.render = function() {
|
||||
this.updatePixelPosition();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @protected
|
||||
*/
|
||||
Overlay.prototype.handleOffsetChanged = function() {
|
||||
this.updatePixelPosition();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @protected
|
||||
*/
|
||||
Overlay.prototype.handlePositionChanged = function() {
|
||||
this.updatePixelPosition();
|
||||
if (this.get(Property.POSITION) && this.autoPan) {
|
||||
this.panIntoView();
|
||||
/**
|
||||
* returns the options this Overlay has been created with
|
||||
* @return {module:ol/Overlay~Options} overlay options
|
||||
*/
|
||||
getOptions() {
|
||||
return this.options;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @protected
|
||||
*/
|
||||
Overlay.prototype.handlePositioningChanged = function() {
|
||||
this.updatePixelPosition();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Set the DOM element to be associated with this overlay.
|
||||
* @param {HTMLElement|undefined} element The Element containing the overlay.
|
||||
* @observable
|
||||
* @api
|
||||
*/
|
||||
Overlay.prototype.setElement = function(element) {
|
||||
this.set(Property.ELEMENT, element);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Set the map to be associated with this overlay.
|
||||
* @param {module:ol/PluggableMap|undefined} map The map that the
|
||||
* overlay is part of.
|
||||
* @observable
|
||||
* @api
|
||||
*/
|
||||
Overlay.prototype.setMap = function(map) {
|
||||
this.set(Property.MAP, map);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Set the offset for this overlay.
|
||||
* @param {Array.<number>} offset Offset.
|
||||
* @observable
|
||||
* @api
|
||||
*/
|
||||
Overlay.prototype.setOffset = function(offset) {
|
||||
this.set(Property.OFFSET, offset);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Set the position for this overlay. If the position is `undefined` the
|
||||
* overlay is hidden.
|
||||
* @param {module:ol/coordinate~Coordinate|undefined} position The spatial point that the overlay
|
||||
* is anchored at.
|
||||
* @observable
|
||||
* @api
|
||||
*/
|
||||
Overlay.prototype.setPosition = function(position) {
|
||||
this.set(Property.POSITION, position);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Pan the map so that the overlay is entirely visible in the current viewport
|
||||
* (if necessary).
|
||||
* @protected
|
||||
*/
|
||||
Overlay.prototype.panIntoView = function() {
|
||||
const map = this.getMap();
|
||||
|
||||
if (!map || !map.getTargetElement()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const mapRect = this.getRect(map.getTargetElement(), map.getSize());
|
||||
const element = this.getElement();
|
||||
const overlayRect = this.getRect(element, [outerWidth(element), outerHeight(element)]);
|
||||
|
||||
const margin = this.autoPanMargin;
|
||||
if (!containsExtent(mapRect, overlayRect)) {
|
||||
// the overlay is not completely inside the viewport, so pan the map
|
||||
const offsetLeft = overlayRect[0] - mapRect[0];
|
||||
const offsetRight = mapRect[2] - overlayRect[2];
|
||||
const offsetTop = overlayRect[1] - mapRect[1];
|
||||
const offsetBottom = mapRect[3] - overlayRect[3];
|
||||
|
||||
const delta = [0, 0];
|
||||
if (offsetLeft < 0) {
|
||||
// move map to the left
|
||||
delta[0] = offsetLeft - margin;
|
||||
} else if (offsetRight < 0) {
|
||||
// move map to the right
|
||||
delta[0] = Math.abs(offsetRight) + margin;
|
||||
}
|
||||
if (offsetTop < 0) {
|
||||
// move map up
|
||||
delta[1] = offsetTop - margin;
|
||||
} else if (offsetBottom < 0) {
|
||||
// move map down
|
||||
delta[1] = Math.abs(offsetBottom) + margin;
|
||||
}
|
||||
|
||||
if (delta[0] !== 0 || delta[1] !== 0) {
|
||||
const center = /** @type {module:ol/coordinate~Coordinate} */ (map.getView().getCenter());
|
||||
const centerPx = map.getPixelFromCoordinate(center);
|
||||
const newCenterPx = [
|
||||
centerPx[0] + delta[0],
|
||||
centerPx[1] + delta[1]
|
||||
];
|
||||
|
||||
map.getView().animate({
|
||||
center: map.getCoordinateFromPixel(newCenterPx),
|
||||
duration: this.autoPanAnimation.duration,
|
||||
easing: this.autoPanAnimation.easing
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get the extent of an element relative to the document
|
||||
* @param {HTMLElement|undefined} element The element.
|
||||
* @param {module:ol/size~Size|undefined} size The size of the element.
|
||||
* @return {module:ol/extent~Extent} The extent.
|
||||
* @protected
|
||||
*/
|
||||
Overlay.prototype.getRect = function(element, size) {
|
||||
const box = element.getBoundingClientRect();
|
||||
const offsetX = box.left + window.pageXOffset;
|
||||
const offsetY = box.top + window.pageYOffset;
|
||||
return [
|
||||
offsetX,
|
||||
offsetY,
|
||||
offsetX + size[0],
|
||||
offsetY + size[1]
|
||||
];
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Set the positioning for this overlay.
|
||||
* @param {module:ol/OverlayPositioning} positioning how the overlay is
|
||||
* positioned relative to its point on the map.
|
||||
* @observable
|
||||
* @api
|
||||
*/
|
||||
Overlay.prototype.setPositioning = function(positioning) {
|
||||
this.set(Property.POSITIONING, positioning);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Modify the visibility of the element.
|
||||
* @param {boolean} visible Element visibility.
|
||||
* @protected
|
||||
*/
|
||||
Overlay.prototype.setVisible = function(visible) {
|
||||
if (this.rendered.visible !== visible) {
|
||||
this.element.style.display = visible ? '' : 'none';
|
||||
this.rendered.visible = visible;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Update pixel position.
|
||||
* @protected
|
||||
*/
|
||||
Overlay.prototype.updatePixelPosition = function() {
|
||||
const map = this.getMap();
|
||||
const position = this.getPosition();
|
||||
if (!map || !map.isRendered() || !position) {
|
||||
this.setVisible(false);
|
||||
return;
|
||||
}
|
||||
|
||||
const pixel = map.getPixelFromCoordinate(position);
|
||||
const mapSize = map.getSize();
|
||||
this.updateRenderedPosition(pixel, mapSize);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {module:ol~Pixel} pixel The pixel location.
|
||||
* @param {module:ol/size~Size|undefined} mapSize The map size.
|
||||
* @protected
|
||||
*/
|
||||
Overlay.prototype.updateRenderedPosition = function(pixel, mapSize) {
|
||||
const style = this.element.style;
|
||||
const offset = this.getOffset();
|
||||
|
||||
const positioning = this.getPositioning();
|
||||
|
||||
this.setVisible(true);
|
||||
|
||||
let offsetX = offset[0];
|
||||
let offsetY = offset[1];
|
||||
if (positioning == OverlayPositioning.BOTTOM_RIGHT ||
|
||||
positioning == OverlayPositioning.CENTER_RIGHT ||
|
||||
positioning == OverlayPositioning.TOP_RIGHT) {
|
||||
if (this.rendered.left_ !== '') {
|
||||
this.rendered.left_ = style.left = '';
|
||||
}
|
||||
const right = Math.round(mapSize[0] - pixel[0] - offsetX) + 'px';
|
||||
if (this.rendered.right_ != right) {
|
||||
this.rendered.right_ = style.right = right;
|
||||
}
|
||||
} else {
|
||||
if (this.rendered.right_ !== '') {
|
||||
this.rendered.right_ = style.right = '';
|
||||
}
|
||||
if (positioning == OverlayPositioning.BOTTOM_CENTER ||
|
||||
positioning == OverlayPositioning.CENTER_CENTER ||
|
||||
positioning == OverlayPositioning.TOP_CENTER) {
|
||||
offsetX -= this.element.offsetWidth / 2;
|
||||
}
|
||||
const left = Math.round(pixel[0] + offsetX) + 'px';
|
||||
if (this.rendered.left_ != left) {
|
||||
this.rendered.left_ = style.left = left;
|
||||
}
|
||||
}
|
||||
if (positioning == OverlayPositioning.BOTTOM_LEFT ||
|
||||
positioning == OverlayPositioning.BOTTOM_CENTER ||
|
||||
positioning == OverlayPositioning.BOTTOM_RIGHT) {
|
||||
if (this.rendered.top_ !== '') {
|
||||
this.rendered.top_ = style.top = '';
|
||||
}
|
||||
const bottom = Math.round(mapSize[1] - pixel[1] - offsetY) + 'px';
|
||||
if (this.rendered.bottom_ != bottom) {
|
||||
this.rendered.bottom_ = style.bottom = bottom;
|
||||
}
|
||||
} else {
|
||||
if (this.rendered.bottom_ !== '') {
|
||||
this.rendered.bottom_ = style.bottom = '';
|
||||
}
|
||||
if (positioning == OverlayPositioning.CENTER_LEFT ||
|
||||
positioning == OverlayPositioning.CENTER_CENTER ||
|
||||
positioning == OverlayPositioning.CENTER_RIGHT) {
|
||||
offsetY -= this.element.offsetHeight / 2;
|
||||
}
|
||||
const top = Math.round(pixel[1] + offsetY) + 'px';
|
||||
if (this.rendered.top_ != top) {
|
||||
this.rendered.top_ = style.top = top;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* returns the options this Overlay has been created with
|
||||
* @return {module:ol/Overlay~Options} overlay options
|
||||
*/
|
||||
Overlay.prototype.getOptions = function() {
|
||||
return this.options;
|
||||
};
|
||||
|
||||
export default Overlay;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
365
src/ol/Tile.js
365
src/ol/Tile.js
@@ -1,7 +1,6 @@
|
||||
/**
|
||||
* @module ol/Tile
|
||||
*/
|
||||
import {inherits} from './util.js';
|
||||
import TileState from './TileState.js';
|
||||
import {easeIn} from './easing.js';
|
||||
import EventTarget from './events/EventTarget.js';
|
||||
@@ -44,221 +43,221 @@ import EventType from './events/EventType.js';
|
||||
* @classdesc
|
||||
* Base class for tiles.
|
||||
*
|
||||
* @constructor
|
||||
* @abstract
|
||||
* @extends {module:ol/events/EventTarget}
|
||||
* @param {module:ol/tilecoord~TileCoord} tileCoord Tile coordinate.
|
||||
* @param {module:ol/TileState} state State.
|
||||
* @param {module:ol/Tile~Options=} opt_options Tile options.
|
||||
*/
|
||||
const Tile = function(tileCoord, state, opt_options) {
|
||||
EventTarget.call(this);
|
||||
|
||||
const options = opt_options ? opt_options : {};
|
||||
*/
|
||||
class Tile extends EventTarget {
|
||||
|
||||
/**
|
||||
* @type {module:ol/tilecoord~TileCoord}
|
||||
* @param {module:ol/tilecoord~TileCoord} tileCoord Tile coordinate.
|
||||
* @param {module:ol/TileState} state State.
|
||||
* @param {module:ol/Tile~Options=} opt_options Tile options.
|
||||
*/
|
||||
this.tileCoord = tileCoord;
|
||||
constructor(tileCoord, state, opt_options) {
|
||||
super();
|
||||
|
||||
const options = opt_options ? opt_options : {};
|
||||
|
||||
/**
|
||||
* @type {module:ol/tilecoord~TileCoord}
|
||||
*/
|
||||
this.tileCoord = tileCoord;
|
||||
|
||||
/**
|
||||
* @protected
|
||||
* @type {module:ol/TileState}
|
||||
*/
|
||||
this.state = state;
|
||||
|
||||
/**
|
||||
* An "interim" tile for this tile. The interim tile may be used while this
|
||||
* one is loading, for "smooth" transitions when changing params/dimensions
|
||||
* on the source.
|
||||
* @type {module:ol/Tile}
|
||||
*/
|
||||
this.interimTile = null;
|
||||
|
||||
/**
|
||||
* A key assigned to the tile. This is used by the tile source to determine
|
||||
* if this tile can effectively be used, or if a new tile should be created
|
||||
* and this one be used as an interim tile for this new tile.
|
||||
* @type {string}
|
||||
*/
|
||||
this.key = '';
|
||||
|
||||
/**
|
||||
* The duration for the opacity transition.
|
||||
* @type {number}
|
||||
*/
|
||||
this.transition_ = options.transition === undefined ? 250 : options.transition;
|
||||
|
||||
/**
|
||||
* Lookup of start times for rendering transitions. If the start time is
|
||||
* equal to -1, the transition is complete.
|
||||
* @type {Object.<number, number>}
|
||||
*/
|
||||
this.transitionStarts_ = {};
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @protected
|
||||
* @type {module:ol/TileState}
|
||||
*/
|
||||
this.state = state;
|
||||
changed() {
|
||||
this.dispatchEvent(EventType.CHANGE);
|
||||
}
|
||||
|
||||
/**
|
||||
* An "interim" tile for this tile. The interim tile may be used while this
|
||||
* one is loading, for "smooth" transitions when changing params/dimensions
|
||||
* on the source.
|
||||
* @type {module:ol/Tile}
|
||||
* @return {string} Key.
|
||||
*/
|
||||
this.interimTile = null;
|
||||
getKey() {
|
||||
return this.key + '/' + this.tileCoord;
|
||||
}
|
||||
|
||||
/**
|
||||
* A key assigned to the tile. This is used by the tile source to determine
|
||||
* if this tile can effectively be used, or if a new tile should be created
|
||||
* and this one be used as an interim tile for this new tile.
|
||||
* @type {string}
|
||||
* Get the interim tile most suitable for rendering using the chain of interim
|
||||
* tiles. This corresponds to the most recent tile that has been loaded, if no
|
||||
* such tile exists, the original tile is returned.
|
||||
* @return {!module:ol/Tile} Best tile for rendering.
|
||||
*/
|
||||
this.key = '';
|
||||
getInterimTile() {
|
||||
if (!this.interimTile) {
|
||||
//empty chain
|
||||
return this;
|
||||
}
|
||||
let tile = this.interimTile;
|
||||
|
||||
/**
|
||||
* The duration for the opacity transition.
|
||||
* @type {number}
|
||||
*/
|
||||
this.transition_ = options.transition === undefined ? 250 : options.transition;
|
||||
// find the first loaded tile and return it. Since the chain is sorted in
|
||||
// decreasing order of creation time, there is no need to search the remainder
|
||||
// of the list (all those tiles correspond to older requests and will be
|
||||
// cleaned up by refreshInterimChain)
|
||||
do {
|
||||
if (tile.getState() == TileState.LOADED) {
|
||||
return tile;
|
||||
}
|
||||
tile = tile.interimTile;
|
||||
} while (tile);
|
||||
|
||||
/**
|
||||
* Lookup of start times for rendering transitions. If the start time is
|
||||
* equal to -1, the transition is complete.
|
||||
* @type {Object.<number, number>}
|
||||
*/
|
||||
this.transitionStarts_ = {};
|
||||
|
||||
};
|
||||
|
||||
inherits(Tile, EventTarget);
|
||||
|
||||
|
||||
/**
|
||||
* @protected
|
||||
*/
|
||||
Tile.prototype.changed = function() {
|
||||
this.dispatchEvent(EventType.CHANGE);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {string} Key.
|
||||
*/
|
||||
Tile.prototype.getKey = function() {
|
||||
return this.key + '/' + this.tileCoord;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the interim tile most suitable for rendering using the chain of interim
|
||||
* tiles. This corresponds to the most recent tile that has been loaded, if no
|
||||
* such tile exists, the original tile is returned.
|
||||
* @return {!module:ol/Tile} Best tile for rendering.
|
||||
*/
|
||||
Tile.prototype.getInterimTile = function() {
|
||||
if (!this.interimTile) {
|
||||
//empty chain
|
||||
// we can not find a better tile
|
||||
return this;
|
||||
}
|
||||
let tile = this.interimTile;
|
||||
|
||||
// find the first loaded tile and return it. Since the chain is sorted in
|
||||
// decreasing order of creation time, there is no need to search the remainder
|
||||
// of the list (all those tiles correspond to older requests and will be
|
||||
// cleaned up by refreshInterimChain)
|
||||
do {
|
||||
if (tile.getState() == TileState.LOADED) {
|
||||
return tile;
|
||||
/**
|
||||
* Goes through the chain of interim tiles and discards sections of the chain
|
||||
* that are no longer relevant.
|
||||
*/
|
||||
refreshInterimChain() {
|
||||
if (!this.interimTile) {
|
||||
return;
|
||||
}
|
||||
tile = tile.interimTile;
|
||||
} while (tile);
|
||||
|
||||
// we can not find a better tile
|
||||
return this;
|
||||
};
|
||||
let tile = this.interimTile;
|
||||
let prev = this;
|
||||
|
||||
/**
|
||||
* Goes through the chain of interim tiles and discards sections of the chain
|
||||
* that are no longer relevant.
|
||||
*/
|
||||
Tile.prototype.refreshInterimChain = function() {
|
||||
if (!this.interimTile) {
|
||||
return;
|
||||
do {
|
||||
if (tile.getState() == TileState.LOADED) {
|
||||
//we have a loaded tile, we can discard the rest of the list
|
||||
//we would could abort any LOADING tile request
|
||||
//older than this tile (i.e. any LOADING tile following this entry in the chain)
|
||||
tile.interimTile = null;
|
||||
break;
|
||||
} else if (tile.getState() == TileState.LOADING) {
|
||||
//keep this LOADING tile any loaded tiles later in the chain are
|
||||
//older than this tile, so we're still interested in the request
|
||||
prev = tile;
|
||||
} else if (tile.getState() == TileState.IDLE) {
|
||||
//the head of the list is the most current tile, we don't need
|
||||
//to start any other requests for this chain
|
||||
prev.interimTile = tile.interimTile;
|
||||
} else {
|
||||
prev = tile;
|
||||
}
|
||||
tile = prev.interimTile;
|
||||
} while (tile);
|
||||
}
|
||||
|
||||
let tile = this.interimTile;
|
||||
let prev = this;
|
||||
/**
|
||||
* Get the tile coordinate for this tile.
|
||||
* @return {module:ol/tilecoord~TileCoord} The tile coordinate.
|
||||
* @api
|
||||
*/
|
||||
getTileCoord() {
|
||||
return this.tileCoord;
|
||||
}
|
||||
|
||||
do {
|
||||
if (tile.getState() == TileState.LOADED) {
|
||||
//we have a loaded tile, we can discard the rest of the list
|
||||
//we would could abort any LOADING tile request
|
||||
//older than this tile (i.e. any LOADING tile following this entry in the chain)
|
||||
tile.interimTile = null;
|
||||
break;
|
||||
} else if (tile.getState() == TileState.LOADING) {
|
||||
//keep this LOADING tile any loaded tiles later in the chain are
|
||||
//older than this tile, so we're still interested in the request
|
||||
prev = tile;
|
||||
} else if (tile.getState() == TileState.IDLE) {
|
||||
//the head of the list is the most current tile, we don't need
|
||||
//to start any other requests for this chain
|
||||
prev.interimTile = tile.interimTile;
|
||||
} else {
|
||||
prev = tile;
|
||||
/**
|
||||
* @return {module:ol/TileState} State.
|
||||
*/
|
||||
getState() {
|
||||
return this.state;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {module:ol/TileState} state State.
|
||||
*/
|
||||
setState(state) {
|
||||
this.state = state;
|
||||
this.changed();
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the image or retry if loading previously failed.
|
||||
* Loading is taken care of by the tile queue, and calling this method is
|
||||
* only needed for preloading or for reloading in case of an error.
|
||||
* @abstract
|
||||
* @api
|
||||
*/
|
||||
load() {}
|
||||
|
||||
/**
|
||||
* Get the alpha value for rendering.
|
||||
* @param {number} id An id for the renderer.
|
||||
* @param {number} time The render frame time.
|
||||
* @return {number} A number between 0 and 1.
|
||||
*/
|
||||
getAlpha(id, time) {
|
||||
if (!this.transition_) {
|
||||
return 1;
|
||||
}
|
||||
tile = prev.interimTile;
|
||||
} while (tile);
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the tile coordinate for this tile.
|
||||
* @return {module:ol/tilecoord~TileCoord} The tile coordinate.
|
||||
* @api
|
||||
*/
|
||||
Tile.prototype.getTileCoord = function() {
|
||||
return this.tileCoord;
|
||||
};
|
||||
let start = this.transitionStarts_[id];
|
||||
if (!start) {
|
||||
start = time;
|
||||
this.transitionStarts_[id] = start;
|
||||
} else if (start === -1) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return {module:ol/TileState} State.
|
||||
*/
|
||||
Tile.prototype.getState = function() {
|
||||
return this.state;
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {module:ol/TileState} state State.
|
||||
*/
|
||||
Tile.prototype.setState = function(state) {
|
||||
this.state = state;
|
||||
this.changed();
|
||||
};
|
||||
|
||||
/**
|
||||
* Load the image or retry if loading previously failed.
|
||||
* Loading is taken care of by the tile queue, and calling this method is
|
||||
* only needed for preloading or for reloading in case of an error.
|
||||
* @abstract
|
||||
* @api
|
||||
*/
|
||||
Tile.prototype.load = function() {};
|
||||
|
||||
/**
|
||||
* Get the alpha value for rendering.
|
||||
* @param {number} id An id for the renderer.
|
||||
* @param {number} time The render frame time.
|
||||
* @return {number} A number between 0 and 1.
|
||||
*/
|
||||
Tile.prototype.getAlpha = function(id, time) {
|
||||
if (!this.transition_) {
|
||||
return 1;
|
||||
const delta = time - start + (1000 / 60); // avoid rendering at 0
|
||||
if (delta >= this.transition_) {
|
||||
return 1;
|
||||
}
|
||||
return easeIn(delta / this.transition_);
|
||||
}
|
||||
|
||||
let start = this.transitionStarts_[id];
|
||||
if (!start) {
|
||||
start = time;
|
||||
this.transitionStarts_[id] = start;
|
||||
} else if (start === -1) {
|
||||
return 1;
|
||||
/**
|
||||
* Determine if a tile is in an alpha transition. A tile is considered in
|
||||
* transition if tile.getAlpha() has not yet been called or has been called
|
||||
* and returned 1.
|
||||
* @param {number} id An id for the renderer.
|
||||
* @return {boolean} The tile is in transition.
|
||||
*/
|
||||
inTransition(id) {
|
||||
if (!this.transition_) {
|
||||
return false;
|
||||
}
|
||||
return this.transitionStarts_[id] !== -1;
|
||||
}
|
||||
|
||||
const delta = time - start + (1000 / 60); // avoid rendering at 0
|
||||
if (delta >= this.transition_) {
|
||||
return 1;
|
||||
/**
|
||||
* Mark a transition as complete.
|
||||
* @param {number} id An id for the renderer.
|
||||
*/
|
||||
endTransition(id) {
|
||||
if (this.transition_) {
|
||||
this.transitionStarts_[id] = -1;
|
||||
}
|
||||
}
|
||||
return easeIn(delta / this.transition_);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if a tile is in an alpha transition. A tile is considered in
|
||||
* transition if tile.getAlpha() has not yet been called or has been called
|
||||
* and returned 1.
|
||||
* @param {number} id An id for the renderer.
|
||||
* @return {boolean} The tile is in transition.
|
||||
*/
|
||||
Tile.prototype.inTransition = function(id) {
|
||||
if (!this.transition_) {
|
||||
return false;
|
||||
}
|
||||
return this.transitionStarts_[id] !== -1;
|
||||
};
|
||||
|
||||
/**
|
||||
* Mark a transition as complete.
|
||||
* @param {number} id An id for the renderer.
|
||||
*/
|
||||
Tile.prototype.endTransition = function(id) {
|
||||
if (this.transition_) {
|
||||
this.transitionStarts_[id] = -1;
|
||||
}
|
||||
};
|
||||
export default Tile;
|
||||
|
||||
@@ -1,56 +1,53 @@
|
||||
/**
|
||||
* @module ol/TileCache
|
||||
*/
|
||||
import {inherits} from './util.js';
|
||||
import LRUCache from './structs/LRUCache.js';
|
||||
import {fromKey, getKey} from './tilecoord.js';
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
* @extends {module:ol/structs/LRUCache.<module:ol/Tile>}
|
||||
* @param {number=} opt_highWaterMark High water mark.
|
||||
* @struct
|
||||
*/
|
||||
const TileCache = function(opt_highWaterMark) {
|
||||
class TileCache extends LRUCache {
|
||||
|
||||
LRUCache.call(this, opt_highWaterMark);
|
||||
/**
|
||||
* @param {number=} opt_highWaterMark High water mark.
|
||||
*/
|
||||
constructor(opt_highWaterMark) {
|
||||
|
||||
};
|
||||
super(opt_highWaterMark);
|
||||
|
||||
inherits(TileCache, LRUCache);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param {!Object.<string, module:ol/TileRange>} usedTiles Used tiles.
|
||||
*/
|
||||
TileCache.prototype.expireCache = function(usedTiles) {
|
||||
while (this.canExpireCache()) {
|
||||
const tile = this.peekLast();
|
||||
const zKey = tile.tileCoord[0].toString();
|
||||
if (zKey in usedTiles && usedTiles[zKey].contains(tile.tileCoord)) {
|
||||
break;
|
||||
} else {
|
||||
this.pop().dispose();
|
||||
/**
|
||||
* @param {!Object.<string, module:ol/TileRange>} usedTiles Used tiles.
|
||||
*/
|
||||
expireCache(usedTiles) {
|
||||
while (this.canExpireCache()) {
|
||||
const tile = this.peekLast();
|
||||
const zKey = tile.tileCoord[0].toString();
|
||||
if (zKey in usedTiles && usedTiles[zKey].contains(tile.tileCoord)) {
|
||||
break;
|
||||
} else {
|
||||
this.pop().dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Prune all tiles from the cache that don't have the same z as the newest tile.
|
||||
*/
|
||||
TileCache.prototype.pruneExceptNewestZ = function() {
|
||||
if (this.getCount() === 0) {
|
||||
return;
|
||||
}
|
||||
const key = this.peekFirstKey();
|
||||
const tileCoord = fromKey(key);
|
||||
const z = tileCoord[0];
|
||||
this.forEach(function(tile) {
|
||||
if (tile.tileCoord[0] !== z) {
|
||||
this.remove(getKey(tile.tileCoord));
|
||||
tile.dispose();
|
||||
/**
|
||||
* Prune all tiles from the cache that don't have the same z as the newest tile.
|
||||
*/
|
||||
pruneExceptNewestZ() {
|
||||
if (this.getCount() === 0) {
|
||||
return;
|
||||
}
|
||||
}, this);
|
||||
};
|
||||
const key = this.peekFirstKey();
|
||||
const tileCoord = fromKey(key);
|
||||
const z = tileCoord[0];
|
||||
this.forEach(function(tile) {
|
||||
if (tile.tileCoord[0] !== z) {
|
||||
this.remove(getKey(tile.tileCoord));
|
||||
tile.dispose();
|
||||
}
|
||||
}, this);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export default TileCache;
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
/**
|
||||
* @module ol/TileQueue
|
||||
*/
|
||||
import {inherits} from './util.js';
|
||||
import TileState from './TileState.js';
|
||||
import {listen, unlisten} from './events.js';
|
||||
import EventType from './events/EventType.js';
|
||||
@@ -13,124 +12,117 @@ import PriorityQueue from './structs/PriorityQueue.js';
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
* @extends {module:ol/structs/PriorityQueue.<Array>}
|
||||
* @param {module:ol/TileQueue~PriorityFunction} tilePriorityFunction
|
||||
* Tile priority function.
|
||||
* @param {function(): ?} tileChangeCallback
|
||||
* Function called on each tile change event.
|
||||
* @struct
|
||||
*/
|
||||
const TileQueue = function(tilePriorityFunction, tileChangeCallback) {
|
||||
class TileQueue extends PriorityQueue {
|
||||
|
||||
/**
|
||||
* @param {module:ol/TileQueue~PriorityFunction} tilePriorityFunction Tile priority function.
|
||||
* @param {function(): ?} tileChangeCallback Function called on each tile change event.
|
||||
*/
|
||||
constructor(tilePriorityFunction, tileChangeCallback) {
|
||||
|
||||
super(
|
||||
/**
|
||||
* @param {Array} element Element.
|
||||
* @return {number} Priority.
|
||||
*/
|
||||
function(element) {
|
||||
return tilePriorityFunction.apply(null, element);
|
||||
},
|
||||
/**
|
||||
* @param {Array} element Element.
|
||||
* @return {string} Key.
|
||||
*/
|
||||
function(element) {
|
||||
return (/** @type {module:ol/Tile} */ (element[0]).getKey());
|
||||
});
|
||||
|
||||
PriorityQueue.call(
|
||||
this,
|
||||
/**
|
||||
* @param {Array} element Element.
|
||||
* @return {number} Priority.
|
||||
* @private
|
||||
* @type {function(): ?}
|
||||
*/
|
||||
function(element) {
|
||||
return tilePriorityFunction.apply(null, element);
|
||||
},
|
||||
this.tileChangeCallback_ = tileChangeCallback;
|
||||
|
||||
/**
|
||||
* @param {Array} element Element.
|
||||
* @return {string} Key.
|
||||
* @private
|
||||
* @type {number}
|
||||
*/
|
||||
function(element) {
|
||||
return (/** @type {module:ol/Tile} */ (element[0]).getKey());
|
||||
});
|
||||
this.tilesLoading_ = 0;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {function(): ?}
|
||||
*/
|
||||
this.tileChangeCallback_ = tileChangeCallback;
|
||||
/**
|
||||
* @private
|
||||
* @type {!Object.<string,boolean>}
|
||||
*/
|
||||
this.tilesLoadingKeys_ = {};
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {number}
|
||||
*/
|
||||
this.tilesLoading_ = 0;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {!Object.<string,boolean>}
|
||||
*/
|
||||
this.tilesLoadingKeys_ = {};
|
||||
|
||||
};
|
||||
|
||||
inherits(TileQueue, PriorityQueue);
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
TileQueue.prototype.enqueue = function(element) {
|
||||
const added = PriorityQueue.prototype.enqueue.call(this, element);
|
||||
if (added) {
|
||||
const tile = element[0];
|
||||
listen(tile, EventType.CHANGE, this.handleTileChange, this);
|
||||
}
|
||||
return added;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {number} Number of tiles loading.
|
||||
*/
|
||||
TileQueue.prototype.getTilesLoading = function() {
|
||||
return this.tilesLoading_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {module:ol/events/Event} event Event.
|
||||
* @protected
|
||||
*/
|
||||
TileQueue.prototype.handleTileChange = function(event) {
|
||||
const tile = /** @type {module:ol/Tile} */ (event.target);
|
||||
const state = tile.getState();
|
||||
if (state === TileState.LOADED || state === TileState.ERROR ||
|
||||
state === TileState.EMPTY || state === TileState.ABORT) {
|
||||
unlisten(tile, EventType.CHANGE, this.handleTileChange, this);
|
||||
const tileKey = tile.getKey();
|
||||
if (tileKey in this.tilesLoadingKeys_) {
|
||||
delete this.tilesLoadingKeys_[tileKey];
|
||||
--this.tilesLoading_;
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
enqueue(element) {
|
||||
const added = super.enqueue(element);
|
||||
if (added) {
|
||||
const tile = element[0];
|
||||
listen(tile, EventType.CHANGE, this.handleTileChange, this);
|
||||
}
|
||||
this.tileChangeCallback_();
|
||||
return added;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @return {number} Number of tiles loading.
|
||||
*/
|
||||
getTilesLoading() {
|
||||
return this.tilesLoading_;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {number} maxTotalLoading Maximum number tiles to load simultaneously.
|
||||
* @param {number} maxNewLoads Maximum number of new tiles to load.
|
||||
*/
|
||||
TileQueue.prototype.loadMoreTiles = function(maxTotalLoading, maxNewLoads) {
|
||||
let newLoads = 0;
|
||||
let abortedTiles = false;
|
||||
let state, tile, tileKey;
|
||||
while (this.tilesLoading_ < maxTotalLoading && newLoads < maxNewLoads &&
|
||||
this.getCount() > 0) {
|
||||
tile = /** @type {module:ol/Tile} */ (this.dequeue()[0]);
|
||||
tileKey = tile.getKey();
|
||||
state = tile.getState();
|
||||
if (state === TileState.ABORT) {
|
||||
abortedTiles = true;
|
||||
} else if (state === TileState.IDLE && !(tileKey in this.tilesLoadingKeys_)) {
|
||||
this.tilesLoadingKeys_[tileKey] = true;
|
||||
++this.tilesLoading_;
|
||||
++newLoads;
|
||||
tile.load();
|
||||
/**
|
||||
* @param {module:ol/events/Event} event Event.
|
||||
* @protected
|
||||
*/
|
||||
handleTileChange(event) {
|
||||
const tile = /** @type {module:ol/Tile} */ (event.target);
|
||||
const state = tile.getState();
|
||||
if (state === TileState.LOADED || state === TileState.ERROR ||
|
||||
state === TileState.EMPTY || state === TileState.ABORT) {
|
||||
unlisten(tile, EventType.CHANGE, this.handleTileChange, this);
|
||||
const tileKey = tile.getKey();
|
||||
if (tileKey in this.tilesLoadingKeys_) {
|
||||
delete this.tilesLoadingKeys_[tileKey];
|
||||
--this.tilesLoading_;
|
||||
}
|
||||
this.tileChangeCallback_();
|
||||
}
|
||||
}
|
||||
if (newLoads === 0 && abortedTiles) {
|
||||
// Do not stop the render loop when all wanted tiles were aborted due to
|
||||
// a small, saturated tile cache.
|
||||
this.tileChangeCallback_();
|
||||
|
||||
/**
|
||||
* @param {number} maxTotalLoading Maximum number tiles to load simultaneously.
|
||||
* @param {number} maxNewLoads Maximum number of new tiles to load.
|
||||
*/
|
||||
loadMoreTiles(maxTotalLoading, maxNewLoads) {
|
||||
let newLoads = 0;
|
||||
let abortedTiles = false;
|
||||
let state, tile, tileKey;
|
||||
while (this.tilesLoading_ < maxTotalLoading && newLoads < maxNewLoads &&
|
||||
this.getCount() > 0) {
|
||||
tile = /** @type {module:ol/Tile} */ (this.dequeue()[0]);
|
||||
tileKey = tile.getKey();
|
||||
state = tile.getState();
|
||||
if (state === TileState.ABORT) {
|
||||
abortedTiles = true;
|
||||
} else if (state === TileState.IDLE && !(tileKey in this.tilesLoadingKeys_)) {
|
||||
this.tilesLoadingKeys_[tileKey] = true;
|
||||
++this.tilesLoading_;
|
||||
++newLoads;
|
||||
tile.load();
|
||||
}
|
||||
}
|
||||
if (newLoads === 0 && abortedTiles) {
|
||||
// Do not stop the render loop when all wanted tiles were aborted due to
|
||||
// a small, saturated tile cache.
|
||||
this.tileChangeCallback_();
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
export default TileQueue;
|
||||
|
||||
@@ -1,40 +1,128 @@
|
||||
/**
|
||||
* @module ol/TileRange
|
||||
*/
|
||||
|
||||
/**
|
||||
* A representation of a contiguous block of tiles. A tile range is specified
|
||||
* by its min/max tile coordinates and is inclusive of coordinates.
|
||||
*
|
||||
* @constructor
|
||||
* @param {number} minX Minimum X.
|
||||
* @param {number} maxX Maximum X.
|
||||
* @param {number} minY Minimum Y.
|
||||
* @param {number} maxY Maximum Y.
|
||||
* @struct
|
||||
*/
|
||||
const TileRange = function(minX, maxX, minY, maxY) {
|
||||
class TileRange {
|
||||
|
||||
/**
|
||||
* @type {number}
|
||||
* @param {number} minX Minimum X.
|
||||
* @param {number} maxX Maximum X.
|
||||
* @param {number} minY Minimum Y.
|
||||
* @param {number} maxY Maximum Y.
|
||||
*/
|
||||
this.minX = minX;
|
||||
constructor(minX, maxX, minY, maxY) {
|
||||
|
||||
/**
|
||||
* @type {number}
|
||||
*/
|
||||
this.minX = minX;
|
||||
|
||||
/**
|
||||
* @type {number}
|
||||
*/
|
||||
this.maxX = maxX;
|
||||
|
||||
/**
|
||||
* @type {number}
|
||||
*/
|
||||
this.minY = minY;
|
||||
|
||||
/**
|
||||
* @type {number}
|
||||
*/
|
||||
this.maxY = maxY;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @type {number}
|
||||
* @param {module:ol/tilecoord~TileCoord} tileCoord Tile coordinate.
|
||||
* @return {boolean} Contains tile coordinate.
|
||||
*/
|
||||
this.maxX = maxX;
|
||||
contains(tileCoord) {
|
||||
return this.containsXY(tileCoord[1], tileCoord[2]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @type {number}
|
||||
* @param {module:ol/TileRange} tileRange Tile range.
|
||||
* @return {boolean} Contains.
|
||||
*/
|
||||
this.minY = minY;
|
||||
containsTileRange(tileRange) {
|
||||
return this.minX <= tileRange.minX && tileRange.maxX <= this.maxX &&
|
||||
this.minY <= tileRange.minY && tileRange.maxY <= this.maxY;
|
||||
}
|
||||
|
||||
/**
|
||||
* @type {number}
|
||||
* @param {number} x Tile coordinate x.
|
||||
* @param {number} y Tile coordinate y.
|
||||
* @return {boolean} Contains coordinate.
|
||||
*/
|
||||
this.maxY = maxY;
|
||||
containsXY(x, y) {
|
||||
return this.minX <= x && x <= this.maxX && this.minY <= y && y <= this.maxY;
|
||||
}
|
||||
|
||||
};
|
||||
/**
|
||||
* @param {module:ol/TileRange} tileRange Tile range.
|
||||
* @return {boolean} Equals.
|
||||
*/
|
||||
equals(tileRange) {
|
||||
return this.minX == tileRange.minX && this.minY == tileRange.minY &&
|
||||
this.maxX == tileRange.maxX && this.maxY == tileRange.maxY;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {module:ol/TileRange} tileRange Tile range.
|
||||
*/
|
||||
extend(tileRange) {
|
||||
if (tileRange.minX < this.minX) {
|
||||
this.minX = tileRange.minX;
|
||||
}
|
||||
if (tileRange.maxX > this.maxX) {
|
||||
this.maxX = tileRange.maxX;
|
||||
}
|
||||
if (tileRange.minY < this.minY) {
|
||||
this.minY = tileRange.minY;
|
||||
}
|
||||
if (tileRange.maxY > this.maxY) {
|
||||
this.maxY = tileRange.maxY;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {number} Height.
|
||||
*/
|
||||
getHeight() {
|
||||
return this.maxY - this.minY + 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {module:ol/size~Size} Size.
|
||||
*/
|
||||
getSize() {
|
||||
return [this.getWidth(), this.getHeight()];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {number} Width.
|
||||
*/
|
||||
getWidth() {
|
||||
return this.maxX - this.minX + 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {module:ol/TileRange} tileRange Tile range.
|
||||
* @return {boolean} Intersects.
|
||||
*/
|
||||
intersects(tileRange) {
|
||||
return this.minX <= tileRange.maxX &&
|
||||
this.maxX >= tileRange.minX &&
|
||||
this.minY <= tileRange.maxY &&
|
||||
this.maxY >= tileRange.minY;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
@@ -58,96 +146,4 @@ export function createOrUpdate(minX, maxX, minY, maxY, tileRange) {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param {module:ol/tilecoord~TileCoord} tileCoord Tile coordinate.
|
||||
* @return {boolean} Contains tile coordinate.
|
||||
*/
|
||||
TileRange.prototype.contains = function(tileCoord) {
|
||||
return this.containsXY(tileCoord[1], tileCoord[2]);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {module:ol/TileRange} tileRange Tile range.
|
||||
* @return {boolean} Contains.
|
||||
*/
|
||||
TileRange.prototype.containsTileRange = function(tileRange) {
|
||||
return this.minX <= tileRange.minX && tileRange.maxX <= this.maxX &&
|
||||
this.minY <= tileRange.minY && tileRange.maxY <= this.maxY;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {number} x Tile coordinate x.
|
||||
* @param {number} y Tile coordinate y.
|
||||
* @return {boolean} Contains coordinate.
|
||||
*/
|
||||
TileRange.prototype.containsXY = function(x, y) {
|
||||
return this.minX <= x && x <= this.maxX && this.minY <= y && y <= this.maxY;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {module:ol/TileRange} tileRange Tile range.
|
||||
* @return {boolean} Equals.
|
||||
*/
|
||||
TileRange.prototype.equals = function(tileRange) {
|
||||
return this.minX == tileRange.minX && this.minY == tileRange.minY &&
|
||||
this.maxX == tileRange.maxX && this.maxY == tileRange.maxY;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {module:ol/TileRange} tileRange Tile range.
|
||||
*/
|
||||
TileRange.prototype.extend = function(tileRange) {
|
||||
if (tileRange.minX < this.minX) {
|
||||
this.minX = tileRange.minX;
|
||||
}
|
||||
if (tileRange.maxX > this.maxX) {
|
||||
this.maxX = tileRange.maxX;
|
||||
}
|
||||
if (tileRange.minY < this.minY) {
|
||||
this.minY = tileRange.minY;
|
||||
}
|
||||
if (tileRange.maxY > this.maxY) {
|
||||
this.maxY = tileRange.maxY;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {number} Height.
|
||||
*/
|
||||
TileRange.prototype.getHeight = function() {
|
||||
return this.maxY - this.minY + 1;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {module:ol/size~Size} Size.
|
||||
*/
|
||||
TileRange.prototype.getSize = function() {
|
||||
return [this.getWidth(), this.getHeight()];
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {number} Width.
|
||||
*/
|
||||
TileRange.prototype.getWidth = function() {
|
||||
return this.maxX - this.minX + 1;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {module:ol/TileRange} tileRange Tile range.
|
||||
* @return {boolean} Intersects.
|
||||
*/
|
||||
TileRange.prototype.intersects = function(tileRange) {
|
||||
return this.minX <= tileRange.maxX &&
|
||||
this.maxX >= tileRange.minX &&
|
||||
this.minY <= tileRange.maxY &&
|
||||
this.maxY >= tileRange.minY;
|
||||
};
|
||||
export default TileRange;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
* @module ol/VectorImageTile
|
||||
*/
|
||||
import {getUid, inherits} from './util.js';
|
||||
import {getUid} from './util.js';
|
||||
import Tile from './Tile.js';
|
||||
import TileState from './TileState.js';
|
||||
import {createCanvasContext2D} from './dom.js';
|
||||
@@ -21,307 +21,299 @@ import {UNDEFINED} from './functions.js';
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
* @extends {module:ol/Tile}
|
||||
* @param {module:ol/tilecoord~TileCoord} tileCoord Tile coordinate.
|
||||
* @param {module:ol/TileState} state State.
|
||||
* @param {number} sourceRevision Source revision.
|
||||
* @param {module:ol/format/Feature} format Feature format.
|
||||
* @param {module:ol/Tile~LoadFunction} tileLoadFunction Tile load function.
|
||||
* @param {module:ol/tilecoord~TileCoord} urlTileCoord Wrapped tile coordinate for source urls.
|
||||
* @param {module:ol/Tile~UrlFunction} tileUrlFunction Tile url function.
|
||||
* @param {module:ol/tilegrid/TileGrid} sourceTileGrid Tile grid of the source.
|
||||
* @param {module:ol/tilegrid/TileGrid} tileGrid Tile grid of the renderer.
|
||||
* @param {Object.<string, module:ol/VectorTile>} sourceTiles Source tiles.
|
||||
* @param {number} pixelRatio Pixel ratio.
|
||||
* @param {module:ol/proj/Projection} projection Projection.
|
||||
* @param {function(new: module:ol/VectorTile, module:ol/tilecoord~TileCoord, module:ol/TileState, string,
|
||||
* module:ol/format/Feature, module:ol/Tile~LoadFunction)} tileClass Class to
|
||||
* instantiate for source tiles.
|
||||
* @param {function(this: module:ol/source/VectorTile, module:ol/events/Event)} handleTileChange
|
||||
* Function to call when a source tile's state changes.
|
||||
* @param {number} zoom Integer zoom to render the tile for.
|
||||
*/
|
||||
const VectorImageTile = function(tileCoord, state, sourceRevision, format,
|
||||
tileLoadFunction, urlTileCoord, tileUrlFunction, sourceTileGrid, tileGrid,
|
||||
sourceTiles, pixelRatio, projection, tileClass, handleTileChange, zoom) {
|
||||
|
||||
Tile.call(this, tileCoord, state, {transition: 0});
|
||||
class VectorImageTile extends Tile {
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {!Object.<string, CanvasRenderingContext2D>}
|
||||
* @param {module:ol/tilecoord~TileCoord} tileCoord Tile coordinate.
|
||||
* @param {module:ol/TileState} state State.
|
||||
* @param {number} sourceRevision Source revision.
|
||||
* @param {module:ol/format/Feature} format Feature format.
|
||||
* @param {module:ol/Tile~LoadFunction} tileLoadFunction Tile load function.
|
||||
* @param {module:ol/tilecoord~TileCoord} urlTileCoord Wrapped tile coordinate for source urls.
|
||||
* @param {module:ol/Tile~UrlFunction} tileUrlFunction Tile url function.
|
||||
* @param {module:ol/tilegrid/TileGrid} sourceTileGrid Tile grid of the source.
|
||||
* @param {module:ol/tilegrid/TileGrid} tileGrid Tile grid of the renderer.
|
||||
* @param {Object.<string, module:ol/VectorTile>} sourceTiles Source tiles.
|
||||
* @param {number} pixelRatio Pixel ratio.
|
||||
* @param {module:ol/proj/Projection} projection Projection.
|
||||
* @param {function(new: module:ol/VectorTile, module:ol/tilecoord~TileCoord, module:ol/TileState, string,
|
||||
* module:ol/format/Feature, module:ol/Tile~LoadFunction)} tileClass Class to
|
||||
* instantiate for source tiles.
|
||||
* @param {function(this: module:ol/source/VectorTile, module:ol/events/Event)} handleTileChange
|
||||
* Function to call when a source tile's state changes.
|
||||
* @param {number} zoom Integer zoom to render the tile for.
|
||||
*/
|
||||
this.context_ = {};
|
||||
constructor(tileCoord, state, sourceRevision, format, tileLoadFunction,
|
||||
urlTileCoord, tileUrlFunction, sourceTileGrid, tileGrid, sourceTiles,
|
||||
pixelRatio, projection, tileClass, handleTileChange, zoom) {
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {module:ol/featureloader~FeatureLoader}
|
||||
*/
|
||||
this.loader_;
|
||||
super(tileCoord, state, {transition: 0});
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {!Object.<string, module:ol/VectorImageTile~ReplayState>}
|
||||
*/
|
||||
this.replayState_ = {};
|
||||
/**
|
||||
* @private
|
||||
* @type {!Object.<string, CanvasRenderingContext2D>}
|
||||
*/
|
||||
this.context_ = {};
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {Object.<string, module:ol/VectorTile>}
|
||||
*/
|
||||
this.sourceTiles_ = sourceTiles;
|
||||
/**
|
||||
* @private
|
||||
* @type {module:ol/featureloader~FeatureLoader}
|
||||
*/
|
||||
this.loader_;
|
||||
|
||||
/**
|
||||
* Keys of source tiles used by this tile. Use with {@link #getTile}.
|
||||
* @type {Array.<string>}
|
||||
*/
|
||||
this.tileKeys = [];
|
||||
/**
|
||||
* @private
|
||||
* @type {!Object.<string, module:ol/VectorImageTile~ReplayState>}
|
||||
*/
|
||||
this.replayState_ = {};
|
||||
|
||||
/**
|
||||
* @type {module:ol/extent~Extent}
|
||||
*/
|
||||
this.extent = null;
|
||||
/**
|
||||
* @private
|
||||
* @type {Object.<string, module:ol/VectorTile>}
|
||||
*/
|
||||
this.sourceTiles_ = sourceTiles;
|
||||
|
||||
/**
|
||||
* @type {number}
|
||||
*/
|
||||
this.sourceRevision_ = sourceRevision;
|
||||
/**
|
||||
* Keys of source tiles used by this tile. Use with {@link #getTile}.
|
||||
* @type {Array.<string>}
|
||||
*/
|
||||
this.tileKeys = [];
|
||||
|
||||
/**
|
||||
* @type {module:ol/tilecoord~TileCoord}
|
||||
*/
|
||||
this.wrappedTileCoord = urlTileCoord;
|
||||
/**
|
||||
* @type {module:ol/extent~Extent}
|
||||
*/
|
||||
this.extent = null;
|
||||
|
||||
/**
|
||||
* @type {Array.<module:ol/events~EventsKey>}
|
||||
*/
|
||||
this.loadListenerKeys_ = [];
|
||||
/**
|
||||
* @type {number}
|
||||
*/
|
||||
this.sourceRevision_ = sourceRevision;
|
||||
|
||||
/**
|
||||
* @type {Array.<module:ol/events~EventsKey>}
|
||||
*/
|
||||
this.sourceTileListenerKeys_ = [];
|
||||
/**
|
||||
* @type {module:ol/tilecoord~TileCoord}
|
||||
*/
|
||||
this.wrappedTileCoord = urlTileCoord;
|
||||
|
||||
if (urlTileCoord) {
|
||||
const extent = this.extent = tileGrid.getTileCoordExtent(urlTileCoord);
|
||||
const resolution = tileGrid.getResolution(zoom);
|
||||
const sourceZ = sourceTileGrid.getZForResolution(resolution);
|
||||
const useLoadedOnly = zoom != tileCoord[0];
|
||||
let loadCount = 0;
|
||||
sourceTileGrid.forEachTileCoord(extent, sourceZ, function(sourceTileCoord) {
|
||||
let sharedExtent = getIntersection(extent,
|
||||
sourceTileGrid.getTileCoordExtent(sourceTileCoord));
|
||||
const sourceExtent = sourceTileGrid.getExtent();
|
||||
if (sourceExtent) {
|
||||
sharedExtent = getIntersection(sharedExtent, sourceExtent, sharedExtent);
|
||||
}
|
||||
if (getWidth(sharedExtent) / resolution >= 0.5 &&
|
||||
getHeight(sharedExtent) / resolution >= 0.5) {
|
||||
// only include source tile if overlap is at least 1 pixel
|
||||
++loadCount;
|
||||
const sourceTileKey = sourceTileCoord.toString();
|
||||
let sourceTile = sourceTiles[sourceTileKey];
|
||||
if (!sourceTile && !useLoadedOnly) {
|
||||
const tileUrl = tileUrlFunction(sourceTileCoord, pixelRatio, projection);
|
||||
sourceTile = sourceTiles[sourceTileKey] = new tileClass(sourceTileCoord,
|
||||
tileUrl == undefined ? TileState.EMPTY : TileState.IDLE,
|
||||
tileUrl == undefined ? '' : tileUrl,
|
||||
format, tileLoadFunction);
|
||||
this.sourceTileListenerKeys_.push(
|
||||
listen(sourceTile, EventType.CHANGE, handleTileChange));
|
||||
/**
|
||||
* @type {Array.<module:ol/events~EventsKey>}
|
||||
*/
|
||||
this.loadListenerKeys_ = [];
|
||||
|
||||
/**
|
||||
* @type {Array.<module:ol/events~EventsKey>}
|
||||
*/
|
||||
this.sourceTileListenerKeys_ = [];
|
||||
|
||||
if (urlTileCoord) {
|
||||
const extent = this.extent = tileGrid.getTileCoordExtent(urlTileCoord);
|
||||
const resolution = tileGrid.getResolution(zoom);
|
||||
const sourceZ = sourceTileGrid.getZForResolution(resolution);
|
||||
const useLoadedOnly = zoom != tileCoord[0];
|
||||
let loadCount = 0;
|
||||
sourceTileGrid.forEachTileCoord(extent, sourceZ, function(sourceTileCoord) {
|
||||
let sharedExtent = getIntersection(extent,
|
||||
sourceTileGrid.getTileCoordExtent(sourceTileCoord));
|
||||
const sourceExtent = sourceTileGrid.getExtent();
|
||||
if (sourceExtent) {
|
||||
sharedExtent = getIntersection(sharedExtent, sourceExtent, sharedExtent);
|
||||
}
|
||||
if (sourceTile && (!useLoadedOnly || sourceTile.getState() == TileState.LOADED)) {
|
||||
sourceTile.consumers++;
|
||||
this.tileKeys.push(sourceTileKey);
|
||||
}
|
||||
}
|
||||
}.bind(this));
|
||||
|
||||
if (useLoadedOnly && loadCount == this.tileKeys.length) {
|
||||
this.finishLoading_();
|
||||
}
|
||||
|
||||
if (zoom <= tileCoord[0] && this.state != TileState.LOADED) {
|
||||
while (zoom > tileGrid.getMinZoom()) {
|
||||
const tile = new VectorImageTile(tileCoord, state, sourceRevision,
|
||||
format, tileLoadFunction, urlTileCoord, tileUrlFunction,
|
||||
sourceTileGrid, tileGrid, sourceTiles, pixelRatio, projection,
|
||||
tileClass, UNDEFINED, --zoom);
|
||||
if (tile.state == TileState.LOADED) {
|
||||
this.interimTile = tile;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
inherits(VectorImageTile, Tile);
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
VectorImageTile.prototype.disposeInternal = function() {
|
||||
this.state = TileState.ABORT;
|
||||
this.changed();
|
||||
if (this.interimTile) {
|
||||
this.interimTile.dispose();
|
||||
}
|
||||
|
||||
for (let i = 0, ii = this.tileKeys.length; i < ii; ++i) {
|
||||
const sourceTileKey = this.tileKeys[i];
|
||||
const sourceTile = this.getTile(sourceTileKey);
|
||||
sourceTile.consumers--;
|
||||
if (sourceTile.consumers == 0) {
|
||||
delete this.sourceTiles_[sourceTileKey];
|
||||
sourceTile.dispose();
|
||||
}
|
||||
}
|
||||
this.tileKeys.length = 0;
|
||||
this.sourceTiles_ = null;
|
||||
this.loadListenerKeys_.forEach(unlistenByKey);
|
||||
this.loadListenerKeys_.length = 0;
|
||||
this.sourceTileListenerKeys_.forEach(unlistenByKey);
|
||||
this.sourceTileListenerKeys_.length = 0;
|
||||
Tile.prototype.disposeInternal.call(this);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {module:ol/layer/Layer} layer Layer.
|
||||
* @return {CanvasRenderingContext2D} The rendering context.
|
||||
*/
|
||||
VectorImageTile.prototype.getContext = function(layer) {
|
||||
const key = getUid(layer).toString();
|
||||
if (!(key in this.context_)) {
|
||||
this.context_[key] = createCanvasContext2D();
|
||||
}
|
||||
return this.context_[key];
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get the Canvas for this tile.
|
||||
* @param {module:ol/layer/Layer} layer Layer.
|
||||
* @return {HTMLCanvasElement} Canvas.
|
||||
*/
|
||||
VectorImageTile.prototype.getImage = function(layer) {
|
||||
return this.getReplayState(layer).renderedTileRevision == -1 ?
|
||||
null : this.getContext(layer).canvas;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {module:ol/layer/Layer} layer Layer.
|
||||
* @return {module:ol/VectorImageTile~ReplayState} The replay state.
|
||||
*/
|
||||
VectorImageTile.prototype.getReplayState = function(layer) {
|
||||
const key = getUid(layer).toString();
|
||||
if (!(key in this.replayState_)) {
|
||||
this.replayState_[key] = {
|
||||
dirty: false,
|
||||
renderedRenderOrder: null,
|
||||
renderedRevision: -1,
|
||||
renderedTileRevision: -1
|
||||
};
|
||||
}
|
||||
return this.replayState_[key];
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
VectorImageTile.prototype.getKey = function() {
|
||||
return this.tileKeys.join('/') + '-' + this.sourceRevision_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {string} tileKey Key (tileCoord) of the source tile.
|
||||
* @return {module:ol/VectorTile} Source tile.
|
||||
*/
|
||||
VectorImageTile.prototype.getTile = function(tileKey) {
|
||||
return this.sourceTiles_[tileKey];
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
VectorImageTile.prototype.load = function() {
|
||||
// Source tiles with LOADED state - we just count them because once they are
|
||||
// loaded, we're no longer listening to state changes.
|
||||
let leftToLoad = 0;
|
||||
// Source tiles with ERROR state - we track them because they can still have
|
||||
// an ERROR state after another load attempt.
|
||||
const errorSourceTiles = {};
|
||||
|
||||
if (this.state == TileState.IDLE) {
|
||||
this.setState(TileState.LOADING);
|
||||
}
|
||||
if (this.state == TileState.LOADING) {
|
||||
this.tileKeys.forEach(function(sourceTileKey) {
|
||||
const sourceTile = this.getTile(sourceTileKey);
|
||||
if (sourceTile.state == TileState.IDLE) {
|
||||
sourceTile.setLoader(this.loader_);
|
||||
sourceTile.load();
|
||||
}
|
||||
if (sourceTile.state == TileState.LOADING) {
|
||||
const key = listen(sourceTile, EventType.CHANGE, function(e) {
|
||||
const state = sourceTile.getState();
|
||||
if (state == TileState.LOADED ||
|
||||
state == TileState.ERROR) {
|
||||
const uid = getUid(sourceTile);
|
||||
if (state == TileState.ERROR) {
|
||||
errorSourceTiles[uid] = true;
|
||||
} else {
|
||||
--leftToLoad;
|
||||
delete errorSourceTiles[uid];
|
||||
}
|
||||
if (leftToLoad - Object.keys(errorSourceTiles).length == 0) {
|
||||
this.finishLoading_();
|
||||
}
|
||||
if (getWidth(sharedExtent) / resolution >= 0.5 &&
|
||||
getHeight(sharedExtent) / resolution >= 0.5) {
|
||||
// only include source tile if overlap is at least 1 pixel
|
||||
++loadCount;
|
||||
const sourceTileKey = sourceTileCoord.toString();
|
||||
let sourceTile = sourceTiles[sourceTileKey];
|
||||
if (!sourceTile && !useLoadedOnly) {
|
||||
const tileUrl = tileUrlFunction(sourceTileCoord, pixelRatio, projection);
|
||||
sourceTile = sourceTiles[sourceTileKey] = new tileClass(sourceTileCoord,
|
||||
tileUrl == undefined ? TileState.EMPTY : TileState.IDLE,
|
||||
tileUrl == undefined ? '' : tileUrl,
|
||||
format, tileLoadFunction);
|
||||
this.sourceTileListenerKeys_.push(
|
||||
listen(sourceTile, EventType.CHANGE, handleTileChange));
|
||||
}
|
||||
}.bind(this));
|
||||
this.loadListenerKeys_.push(key);
|
||||
++leftToLoad;
|
||||
if (sourceTile && (!useLoadedOnly || sourceTile.getState() == TileState.LOADED)) {
|
||||
sourceTile.consumers++;
|
||||
this.tileKeys.push(sourceTileKey);
|
||||
}
|
||||
}
|
||||
}.bind(this));
|
||||
|
||||
if (useLoadedOnly && loadCount == this.tileKeys.length) {
|
||||
this.finishLoading_();
|
||||
}
|
||||
}.bind(this));
|
||||
}
|
||||
if (leftToLoad - Object.keys(errorSourceTiles).length == 0) {
|
||||
setTimeout(this.finishLoading_.bind(this), 0);
|
||||
}
|
||||
};
|
||||
|
||||
if (zoom <= tileCoord[0] && this.state != TileState.LOADED) {
|
||||
while (zoom > tileGrid.getMinZoom()) {
|
||||
const tile = new VectorImageTile(tileCoord, state, sourceRevision,
|
||||
format, tileLoadFunction, urlTileCoord, tileUrlFunction,
|
||||
sourceTileGrid, tileGrid, sourceTiles, pixelRatio, projection,
|
||||
tileClass, UNDEFINED, --zoom);
|
||||
if (tile.state == TileState.LOADED) {
|
||||
this.interimTile = tile;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
VectorImageTile.prototype.finishLoading_ = function() {
|
||||
let loaded = this.tileKeys.length;
|
||||
let empty = 0;
|
||||
for (let i = loaded - 1; i >= 0; --i) {
|
||||
const state = this.getTile(this.tileKeys[i]).getState();
|
||||
if (state != TileState.LOADED) {
|
||||
--loaded;
|
||||
}
|
||||
if (state == TileState.EMPTY) {
|
||||
++empty;
|
||||
}
|
||||
}
|
||||
if (loaded == this.tileKeys.length) {
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
disposeInternal() {
|
||||
this.state = TileState.ABORT;
|
||||
this.changed();
|
||||
if (this.interimTile) {
|
||||
this.interimTile.dispose();
|
||||
}
|
||||
|
||||
for (let i = 0, ii = this.tileKeys.length; i < ii; ++i) {
|
||||
const sourceTileKey = this.tileKeys[i];
|
||||
const sourceTile = this.getTile(sourceTileKey);
|
||||
sourceTile.consumers--;
|
||||
if (sourceTile.consumers == 0) {
|
||||
delete this.sourceTiles_[sourceTileKey];
|
||||
sourceTile.dispose();
|
||||
}
|
||||
}
|
||||
this.tileKeys.length = 0;
|
||||
this.sourceTiles_ = null;
|
||||
this.loadListenerKeys_.forEach(unlistenByKey);
|
||||
this.loadListenerKeys_.length = 0;
|
||||
this.setState(TileState.LOADED);
|
||||
} else {
|
||||
this.setState(empty == this.tileKeys.length ? TileState.EMPTY : TileState.ERROR);
|
||||
this.sourceTileListenerKeys_.forEach(unlistenByKey);
|
||||
this.sourceTileListenerKeys_.length = 0;
|
||||
super.disposeInternal();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {module:ol/layer/Layer} layer Layer.
|
||||
* @return {CanvasRenderingContext2D} The rendering context.
|
||||
*/
|
||||
getContext(layer) {
|
||||
const key = getUid(layer).toString();
|
||||
if (!(key in this.context_)) {
|
||||
this.context_[key] = createCanvasContext2D();
|
||||
}
|
||||
return this.context_[key];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Canvas for this tile.
|
||||
* @param {module:ol/layer/Layer} layer Layer.
|
||||
* @return {HTMLCanvasElement} Canvas.
|
||||
*/
|
||||
getImage(layer) {
|
||||
return this.getReplayState(layer).renderedTileRevision == -1 ?
|
||||
null : this.getContext(layer).canvas;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {module:ol/layer/Layer} layer Layer.
|
||||
* @return {module:ol/VectorImageTile~ReplayState} The replay state.
|
||||
*/
|
||||
getReplayState(layer) {
|
||||
const key = getUid(layer).toString();
|
||||
if (!(key in this.replayState_)) {
|
||||
this.replayState_[key] = {
|
||||
dirty: false,
|
||||
renderedRenderOrder: null,
|
||||
renderedRevision: -1,
|
||||
renderedTileRevision: -1
|
||||
};
|
||||
}
|
||||
return this.replayState_[key];
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
getKey() {
|
||||
return this.tileKeys.join('/') + '-' + this.sourceRevision_;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} tileKey Key (tileCoord) of the source tile.
|
||||
* @return {module:ol/VectorTile} Source tile.
|
||||
*/
|
||||
getTile(tileKey) {
|
||||
return this.sourceTiles_[tileKey];
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
load() {
|
||||
// Source tiles with LOADED state - we just count them because once they are
|
||||
// loaded, we're no longer listening to state changes.
|
||||
let leftToLoad = 0;
|
||||
// Source tiles with ERROR state - we track them because they can still have
|
||||
// an ERROR state after another load attempt.
|
||||
const errorSourceTiles = {};
|
||||
|
||||
if (this.state == TileState.IDLE) {
|
||||
this.setState(TileState.LOADING);
|
||||
}
|
||||
if (this.state == TileState.LOADING) {
|
||||
this.tileKeys.forEach(function(sourceTileKey) {
|
||||
const sourceTile = this.getTile(sourceTileKey);
|
||||
if (sourceTile.state == TileState.IDLE) {
|
||||
sourceTile.setLoader(this.loader_);
|
||||
sourceTile.load();
|
||||
}
|
||||
if (sourceTile.state == TileState.LOADING) {
|
||||
const key = listen(sourceTile, EventType.CHANGE, function(e) {
|
||||
const state = sourceTile.getState();
|
||||
if (state == TileState.LOADED ||
|
||||
state == TileState.ERROR) {
|
||||
const uid = getUid(sourceTile);
|
||||
if (state == TileState.ERROR) {
|
||||
errorSourceTiles[uid] = true;
|
||||
} else {
|
||||
--leftToLoad;
|
||||
delete errorSourceTiles[uid];
|
||||
}
|
||||
if (leftToLoad - Object.keys(errorSourceTiles).length == 0) {
|
||||
this.finishLoading_();
|
||||
}
|
||||
}
|
||||
}.bind(this));
|
||||
this.loadListenerKeys_.push(key);
|
||||
++leftToLoad;
|
||||
}
|
||||
}.bind(this));
|
||||
}
|
||||
if (leftToLoad - Object.keys(errorSourceTiles).length == 0) {
|
||||
setTimeout(this.finishLoading_.bind(this), 0);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
finishLoading_() {
|
||||
let loaded = this.tileKeys.length;
|
||||
let empty = 0;
|
||||
for (let i = loaded - 1; i >= 0; --i) {
|
||||
const state = this.getTile(this.tileKeys[i]).getState();
|
||||
if (state != TileState.LOADED) {
|
||||
--loaded;
|
||||
}
|
||||
if (state == TileState.EMPTY) {
|
||||
++empty;
|
||||
}
|
||||
}
|
||||
if (loaded == this.tileKeys.length) {
|
||||
this.loadListenerKeys_.forEach(unlistenByKey);
|
||||
this.loadListenerKeys_.length = 0;
|
||||
this.setState(TileState.LOADED);
|
||||
} else {
|
||||
this.setState(empty == this.tileKeys.length ? TileState.EMPTY : TileState.ERROR);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export default VectorImageTile;
|
||||
|
||||
|
||||
@@ -1,88 +1,10 @@
|
||||
/**
|
||||
* @module ol/VectorTile
|
||||
*/
|
||||
import {getUid, inherits} from './util.js';
|
||||
import {getUid} from './util.js';
|
||||
import Tile from './Tile.js';
|
||||
import TileState from './TileState.js';
|
||||
|
||||
/**
|
||||
* @typedef {function(new: module:ol/VectorTile, module:ol/tilecoord~TileCoord,
|
||||
* module:ol/TileState, string, ?string, module:ol/Tile~LoadFunction)} TileClass
|
||||
* @api
|
||||
*/
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
* @extends {module:ol/Tile}
|
||||
* @param {module:ol/tilecoord~TileCoord} tileCoord Tile coordinate.
|
||||
* @param {module:ol/TileState} state State.
|
||||
* @param {string} src Data source url.
|
||||
* @param {module:ol/format/Feature} format Feature format.
|
||||
* @param {module:ol/Tile~LoadFunction} tileLoadFunction Tile load function.
|
||||
* @param {module:ol/Tile~Options=} opt_options Tile options.
|
||||
*/
|
||||
const VectorTile = function(tileCoord, state, src, format, tileLoadFunction, opt_options) {
|
||||
|
||||
Tile.call(this, tileCoord, state, opt_options);
|
||||
|
||||
/**
|
||||
* @type {number}
|
||||
*/
|
||||
this.consumers = 0;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {module:ol/extent~Extent}
|
||||
*/
|
||||
this.extent_ = null;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {module:ol/format/Feature}
|
||||
*/
|
||||
this.format_ = format;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {Array.<module:ol/Feature>}
|
||||
*/
|
||||
this.features_ = null;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {module:ol/featureloader~FeatureLoader}
|
||||
*/
|
||||
this.loader_;
|
||||
|
||||
/**
|
||||
* Data projection
|
||||
* @private
|
||||
* @type {module:ol/proj/Projection}
|
||||
*/
|
||||
this.projection_ = null;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {Object.<string, module:ol/render/ReplayGroup>}
|
||||
*/
|
||||
this.replayGroups_ = {};
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {module:ol/Tile~LoadFunction}
|
||||
*/
|
||||
this.tileLoadFunction_ = tileLoadFunction;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {string}
|
||||
*/
|
||||
this.url_ = src;
|
||||
|
||||
};
|
||||
|
||||
inherits(VectorTile, Tile);
|
||||
|
||||
/**
|
||||
* @const
|
||||
* @type {module:ol/extent~Extent}
|
||||
@@ -91,168 +13,231 @@ const DEFAULT_EXTENT = [0, 0, 4096, 4096];
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
VectorTile.prototype.disposeInternal = function() {
|
||||
this.features_ = null;
|
||||
this.replayGroups_ = {};
|
||||
this.state = TileState.ABORT;
|
||||
this.changed();
|
||||
Tile.prototype.disposeInternal.call(this);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Gets the extent of the vector tile.
|
||||
* @return {module:ol/extent~Extent} The extent.
|
||||
* @typedef {function(new: module:ol/VectorTile, module:ol/tilecoord~TileCoord,
|
||||
* module:ol/TileState, string, ?string, module:ol/Tile~LoadFunction)} TileClass
|
||||
* @api
|
||||
*/
|
||||
VectorTile.prototype.getExtent = function() {
|
||||
return this.extent_ || DEFAULT_EXTENT;
|
||||
};
|
||||
|
||||
class VectorTile extends Tile {
|
||||
|
||||
/**
|
||||
* Get the feature format assigned for reading this tile's features.
|
||||
* @return {module:ol/format/Feature} Feature format.
|
||||
* @api
|
||||
*/
|
||||
VectorTile.prototype.getFormat = function() {
|
||||
return this.format_;
|
||||
};
|
||||
/**
|
||||
* @param {module:ol/tilecoord~TileCoord} tileCoord Tile coordinate.
|
||||
* @param {module:ol/TileState} state State.
|
||||
* @param {string} src Data source url.
|
||||
* @param {module:ol/format/Feature} format Feature format.
|
||||
* @param {module:ol/Tile~LoadFunction} tileLoadFunction Tile load function.
|
||||
* @param {module:ol/Tile~Options=} opt_options Tile options.
|
||||
*/
|
||||
constructor(tileCoord, state, src, format, tileLoadFunction, opt_options) {
|
||||
|
||||
super(tileCoord, state, opt_options);
|
||||
|
||||
/**
|
||||
* Get the features for this tile. Geometries will be in the projection returned
|
||||
* by {@link module:ol/VectorTile~VectorTile#getProjection}.
|
||||
* @return {Array.<module:ol/Feature|module:ol/render/Feature>} Features.
|
||||
* @api
|
||||
*/
|
||||
VectorTile.prototype.getFeatures = function() {
|
||||
return this.features_;
|
||||
};
|
||||
/**
|
||||
* @type {number}
|
||||
*/
|
||||
this.consumers = 0;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {module:ol/extent~Extent}
|
||||
*/
|
||||
this.extent_ = null;
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
VectorTile.prototype.getKey = function() {
|
||||
return this.url_;
|
||||
};
|
||||
/**
|
||||
* @private
|
||||
* @type {module:ol/format/Feature}
|
||||
*/
|
||||
this.format_ = format;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {Array.<module:ol/Feature>}
|
||||
*/
|
||||
this.features_ = null;
|
||||
|
||||
/**
|
||||
* Get the feature projection of features returned by
|
||||
* {@link module:ol/VectorTile~VectorTile#getFeatures}.
|
||||
* @return {module:ol/proj/Projection} Feature projection.
|
||||
* @api
|
||||
*/
|
||||
VectorTile.prototype.getProjection = function() {
|
||||
return this.projection_;
|
||||
};
|
||||
/**
|
||||
* @private
|
||||
* @type {module:ol/featureloader~FeatureLoader}
|
||||
*/
|
||||
this.loader_;
|
||||
|
||||
/**
|
||||
* Data projection
|
||||
* @private
|
||||
* @type {module:ol/proj/Projection}
|
||||
*/
|
||||
this.projection_ = null;
|
||||
|
||||
/**
|
||||
* @param {module:ol/layer/Layer} layer Layer.
|
||||
* @param {string} key Key.
|
||||
* @return {module:ol/render/ReplayGroup} Replay group.
|
||||
*/
|
||||
VectorTile.prototype.getReplayGroup = function(layer, key) {
|
||||
return this.replayGroups_[getUid(layer) + ',' + key];
|
||||
};
|
||||
/**
|
||||
* @private
|
||||
* @type {Object.<string, module:ol/render/ReplayGroup>}
|
||||
*/
|
||||
this.replayGroups_ = {};
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {module:ol/Tile~LoadFunction}
|
||||
*/
|
||||
this.tileLoadFunction_ = tileLoadFunction;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {string}
|
||||
*/
|
||||
this.url_ = src;
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
VectorTile.prototype.load = function() {
|
||||
if (this.state == TileState.IDLE) {
|
||||
this.setState(TileState.LOADING);
|
||||
this.tileLoadFunction_(this, this.url_);
|
||||
this.loader_(null, NaN, null);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
disposeInternal() {
|
||||
this.features_ = null;
|
||||
this.replayGroups_ = {};
|
||||
this.state = TileState.ABORT;
|
||||
this.changed();
|
||||
super.disposeInternal();
|
||||
}
|
||||
|
||||
/**
|
||||
* Handler for successful tile load.
|
||||
* @param {Array.<module:ol/Feature>} features The loaded features.
|
||||
* @param {module:ol/proj/Projection} dataProjection Data projection.
|
||||
* @param {module:ol/extent~Extent} extent Extent.
|
||||
*/
|
||||
VectorTile.prototype.onLoad = function(features, dataProjection, extent) {
|
||||
this.setProjection(dataProjection);
|
||||
this.setFeatures(features);
|
||||
this.setExtent(extent);
|
||||
};
|
||||
/**
|
||||
* Gets the extent of the vector tile.
|
||||
* @return {module:ol/extent~Extent} The extent.
|
||||
* @api
|
||||
*/
|
||||
getExtent() {
|
||||
return this.extent_ || DEFAULT_EXTENT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the feature format assigned for reading this tile's features.
|
||||
* @return {module:ol/format/Feature} Feature format.
|
||||
* @api
|
||||
*/
|
||||
getFormat() {
|
||||
return this.format_;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handler for tile load errors.
|
||||
*/
|
||||
VectorTile.prototype.onError = function() {
|
||||
this.setState(TileState.ERROR);
|
||||
};
|
||||
/**
|
||||
* Get the features for this tile. Geometries will be in the projection returned
|
||||
* by {@link module:ol/VectorTile~VectorTile#getProjection}.
|
||||
* @return {Array.<module:ol/Feature|module:ol/render/Feature>} Features.
|
||||
* @api
|
||||
*/
|
||||
getFeatures() {
|
||||
return this.features_;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
getKey() {
|
||||
return this.url_;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function for use in an {@link module:ol/source/VectorTile~VectorTile}'s
|
||||
* `tileLoadFunction`. Sets the extent of the vector tile. This is only required
|
||||
* for tiles in projections with `tile-pixels` as units. The extent should be
|
||||
* set to `[0, 0, tilePixelSize, tilePixelSize]`, where `tilePixelSize` is
|
||||
* calculated by multiplying the tile size with the tile pixel ratio. For
|
||||
* sources using {@link module:ol/format/MVT~MVT} as feature format, the
|
||||
* {@link module:ol/format/MVT~MVT#getLastExtent} method will return the correct
|
||||
* extent. The default is `[0, 0, 4096, 4096]`.
|
||||
* @param {module:ol/extent~Extent} extent The extent.
|
||||
* @api
|
||||
*/
|
||||
VectorTile.prototype.setExtent = function(extent) {
|
||||
this.extent_ = extent;
|
||||
};
|
||||
/**
|
||||
* Get the feature projection of features returned by
|
||||
* {@link module:ol/VectorTile~VectorTile#getFeatures}.
|
||||
* @return {module:ol/proj/Projection} Feature projection.
|
||||
* @api
|
||||
*/
|
||||
getProjection() {
|
||||
return this.projection_;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {module:ol/layer/Layer} layer Layer.
|
||||
* @param {string} key Key.
|
||||
* @return {module:ol/render/ReplayGroup} Replay group.
|
||||
*/
|
||||
getReplayGroup(layer, key) {
|
||||
return this.replayGroups_[getUid(layer) + ',' + key];
|
||||
}
|
||||
|
||||
/**
|
||||
* Function for use in an {@link module:ol/source/VectorTile~VectorTile}'s `tileLoadFunction`.
|
||||
* Sets the features for the tile.
|
||||
* @param {Array.<module:ol/Feature>} features Features.
|
||||
* @api
|
||||
*/
|
||||
VectorTile.prototype.setFeatures = function(features) {
|
||||
this.features_ = features;
|
||||
this.setState(TileState.LOADED);
|
||||
};
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
load() {
|
||||
if (this.state == TileState.IDLE) {
|
||||
this.setState(TileState.LOADING);
|
||||
this.tileLoadFunction_(this, this.url_);
|
||||
this.loader_(null, NaN, null);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handler for successful tile load.
|
||||
* @param {Array.<module:ol/Feature>} features The loaded features.
|
||||
* @param {module:ol/proj/Projection} dataProjection Data projection.
|
||||
* @param {module:ol/extent~Extent} extent Extent.
|
||||
*/
|
||||
onLoad(features, dataProjection, extent) {
|
||||
this.setProjection(dataProjection);
|
||||
this.setFeatures(features);
|
||||
this.setExtent(extent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Function for use in an {@link module:ol/source/VectorTile~VectorTile}'s `tileLoadFunction`.
|
||||
* Sets the projection of the features that were added with
|
||||
* {@link module:ol/VectorTile~VectorTile#setFeatures}.
|
||||
* @param {module:ol/proj/Projection} projection Feature projection.
|
||||
* @api
|
||||
*/
|
||||
VectorTile.prototype.setProjection = function(projection) {
|
||||
this.projection_ = projection;
|
||||
};
|
||||
/**
|
||||
* Handler for tile load errors.
|
||||
*/
|
||||
onError() {
|
||||
this.setState(TileState.ERROR);
|
||||
}
|
||||
|
||||
/**
|
||||
* Function for use in an {@link module:ol/source/VectorTile~VectorTile}'s
|
||||
* `tileLoadFunction`. Sets the extent of the vector tile. This is only required
|
||||
* for tiles in projections with `tile-pixels` as units. The extent should be
|
||||
* set to `[0, 0, tilePixelSize, tilePixelSize]`, where `tilePixelSize` is
|
||||
* calculated by multiplying the tile size with the tile pixel ratio. For
|
||||
* sources using {@link module:ol/format/MVT~MVT} as feature format, the
|
||||
* {@link module:ol/format/MVT~MVT#getLastExtent} method will return the correct
|
||||
* extent. The default is `[0, 0, 4096, 4096]`.
|
||||
* @param {module:ol/extent~Extent} extent The extent.
|
||||
* @api
|
||||
*/
|
||||
setExtent(extent) {
|
||||
this.extent_ = extent;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {module:ol/layer/Layer} layer Layer.
|
||||
* @param {string} key Key.
|
||||
* @param {module:ol/render/ReplayGroup} replayGroup Replay group.
|
||||
*/
|
||||
VectorTile.prototype.setReplayGroup = function(layer, key, replayGroup) {
|
||||
this.replayGroups_[getUid(layer) + ',' + key] = replayGroup;
|
||||
};
|
||||
/**
|
||||
* Function for use in an {@link module:ol/source/VectorTile~VectorTile}'s `tileLoadFunction`.
|
||||
* Sets the features for the tile.
|
||||
* @param {Array.<module:ol/Feature>} features Features.
|
||||
* @api
|
||||
*/
|
||||
setFeatures(features) {
|
||||
this.features_ = features;
|
||||
this.setState(TileState.LOADED);
|
||||
}
|
||||
|
||||
/**
|
||||
* Function for use in an {@link module:ol/source/VectorTile~VectorTile}'s `tileLoadFunction`.
|
||||
* Sets the projection of the features that were added with
|
||||
* {@link module:ol/VectorTile~VectorTile#setFeatures}.
|
||||
* @param {module:ol/proj/Projection} projection Feature projection.
|
||||
* @api
|
||||
*/
|
||||
setProjection(projection) {
|
||||
this.projection_ = projection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the feature loader for reading this tile's features.
|
||||
* @param {module:ol/featureloader~FeatureLoader} loader Feature loader.
|
||||
* @api
|
||||
*/
|
||||
VectorTile.prototype.setLoader = function(loader) {
|
||||
this.loader_ = loader;
|
||||
};
|
||||
/**
|
||||
* @param {module:ol/layer/Layer} layer Layer.
|
||||
* @param {string} key Key.
|
||||
* @param {module:ol/render/ReplayGroup} replayGroup Replay group.
|
||||
*/
|
||||
setReplayGroup(layer, key, replayGroup) {
|
||||
this.replayGroups_[getUid(layer) + ',' + key] = replayGroup;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the feature loader for reading this tile's features.
|
||||
* @param {module:ol/featureloader~FeatureLoader} loader Feature loader.
|
||||
* @api
|
||||
*/
|
||||
setLoader(loader) {
|
||||
this.loader_ = loader;
|
||||
}
|
||||
}
|
||||
|
||||
export default VectorTile;
|
||||
|
||||
1807
src/ol/View.js
1807
src/ol/View.js
File diff suppressed because it is too large
Load Diff
@@ -1,7 +1,6 @@
|
||||
/**
|
||||
* @module ol/WebGLMap
|
||||
*/
|
||||
import {inherits} from './util.js';
|
||||
import PluggableMap from './PluggableMap.js';
|
||||
import {defaults as defaultControls} from './control.js';
|
||||
import {defaults as defaultInteractions} from './interaction.js';
|
||||
@@ -57,38 +56,39 @@ import WebGLVectorLayerRenderer from './renderer/webgl/VectorLayer.js';
|
||||
* {@link module:ol/layer/Base}, so layers entered in the options or added
|
||||
* with `addLayer` can be groups, which can contain further groups, and so on.
|
||||
*
|
||||
* @constructor
|
||||
* @extends {module:ol/PluggableMap}
|
||||
* @param {module:ol/PluggableMap~MapOptions} options Map options.
|
||||
* @fires module:ol/MapBrowserEvent~MapBrowserEvent
|
||||
* @fires module:ol/MapEvent~MapEvent
|
||||
* @fires module:ol/render/Event~RenderEvent#postcompose
|
||||
* @fires module:ol/render/Event~RenderEvent#precompose
|
||||
* @api
|
||||
*/
|
||||
const WebGLMap = function(options) {
|
||||
options = assign({}, options);
|
||||
if (!options.controls) {
|
||||
options.controls = defaultControls();
|
||||
}
|
||||
if (!options.interactions) {
|
||||
options.interactions = defaultInteractions();
|
||||
class WebGLMap extends PluggableMap {
|
||||
|
||||
/**
|
||||
* @param {module:ol/PluggableMap~MapOptions} options Map options.
|
||||
*/
|
||||
constructor(options) {
|
||||
options = assign({}, options);
|
||||
if (!options.controls) {
|
||||
options.controls = defaultControls();
|
||||
}
|
||||
if (!options.interactions) {
|
||||
options.interactions = defaultInteractions();
|
||||
}
|
||||
|
||||
super(options);
|
||||
}
|
||||
|
||||
PluggableMap.call(this, options);
|
||||
};
|
||||
createRenderer() {
|
||||
const renderer = new WebGLMapRenderer(this);
|
||||
renderer.registerLayerRenderers([
|
||||
WebGLImageLayerRenderer,
|
||||
WebGLTileLayerRenderer,
|
||||
WebGLVectorLayerRenderer
|
||||
]);
|
||||
return renderer;
|
||||
}
|
||||
}
|
||||
|
||||
inherits(WebGLMap, PluggableMap);
|
||||
|
||||
|
||||
WebGLMap.prototype.createRenderer = function() {
|
||||
const renderer = new WebGLMapRenderer(this);
|
||||
renderer.registerLayerRenderers([
|
||||
WebGLImageLayerRenderer,
|
||||
WebGLTileLayerRenderer,
|
||||
WebGLVectorLayerRenderer
|
||||
]);
|
||||
return renderer;
|
||||
};
|
||||
|
||||
export default WebGLMap;
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
/**
|
||||
* @module ol/control/Attribution
|
||||
*/
|
||||
import {inherits} from '../util.js';
|
||||
import {equals} from '../array.js';
|
||||
import Control from '../control/Control.js';
|
||||
import {CLASS_CONTROL, CLASS_UNSELECTABLE, CLASS_COLLAPSED} from '../css.js';
|
||||
@@ -42,168 +41,276 @@ import {visibleAtResolution} from '../layer/Layer.js';
|
||||
* By default it will show in the bottom right portion of the map, but this can
|
||||
* be changed by using a css selector for `.ol-attribution`.
|
||||
*
|
||||
* @constructor
|
||||
* @extends {module:ol/control/Control}
|
||||
* @param {module:ol/control/Attribution~Options=} opt_options Attribution options.
|
||||
* @api
|
||||
*/
|
||||
const Attribution = function(opt_options) {
|
||||
|
||||
const options = opt_options ? opt_options : {};
|
||||
class Attribution extends Control {
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {Element}
|
||||
* @param {module:ol/control/Attribution~Options=} opt_options Attribution options.
|
||||
*/
|
||||
this.ulElement_ = document.createElement('UL');
|
||||
constructor(opt_options) {
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.collapsed_ = options.collapsed !== undefined ? options.collapsed : true;
|
||||
const options = opt_options ? opt_options : {};
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.collapsible_ = options.collapsible !== undefined ?
|
||||
options.collapsible : true;
|
||||
super({
|
||||
element: document.createElement('div'),
|
||||
render: options.render || render,
|
||||
target: options.target
|
||||
});
|
||||
|
||||
if (!this.collapsible_) {
|
||||
this.collapsed_ = false;
|
||||
}
|
||||
|
||||
const className = options.className !== undefined ? options.className : 'ol-attribution';
|
||||
|
||||
const tipLabel = options.tipLabel !== undefined ? options.tipLabel : 'Attributions';
|
||||
|
||||
const collapseLabel = options.collapseLabel !== undefined ? options.collapseLabel : '\u00BB';
|
||||
|
||||
if (typeof collapseLabel === 'string') {
|
||||
/**
|
||||
* @private
|
||||
* @type {Element}
|
||||
*/
|
||||
this.collapseLabel_ = document.createElement('span');
|
||||
this.collapseLabel_.textContent = collapseLabel;
|
||||
} else {
|
||||
this.collapseLabel_ = collapseLabel;
|
||||
}
|
||||
this.ulElement_ = document.createElement('UL');
|
||||
|
||||
const label = options.label !== undefined ? options.label : 'i';
|
||||
|
||||
if (typeof label === 'string') {
|
||||
/**
|
||||
* @private
|
||||
* @type {Element}
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.label_ = document.createElement('span');
|
||||
this.label_.textContent = label;
|
||||
} else {
|
||||
this.label_ = label;
|
||||
this.collapsed_ = options.collapsed !== undefined ? options.collapsed : true;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.collapsible_ = options.collapsible !== undefined ?
|
||||
options.collapsible : true;
|
||||
|
||||
if (!this.collapsible_) {
|
||||
this.collapsed_ = false;
|
||||
}
|
||||
|
||||
const className = options.className !== undefined ? options.className : 'ol-attribution';
|
||||
|
||||
const tipLabel = options.tipLabel !== undefined ? options.tipLabel : 'Attributions';
|
||||
|
||||
const collapseLabel = options.collapseLabel !== undefined ? options.collapseLabel : '\u00BB';
|
||||
|
||||
if (typeof collapseLabel === 'string') {
|
||||
/**
|
||||
* @private
|
||||
* @type {Element}
|
||||
*/
|
||||
this.collapseLabel_ = document.createElement('span');
|
||||
this.collapseLabel_.textContent = collapseLabel;
|
||||
} else {
|
||||
this.collapseLabel_ = collapseLabel;
|
||||
}
|
||||
|
||||
const label = options.label !== undefined ? options.label : 'i';
|
||||
|
||||
if (typeof label === 'string') {
|
||||
/**
|
||||
* @private
|
||||
* @type {Element}
|
||||
*/
|
||||
this.label_ = document.createElement('span');
|
||||
this.label_.textContent = label;
|
||||
} else {
|
||||
this.label_ = label;
|
||||
}
|
||||
|
||||
|
||||
const activeLabel = (this.collapsible_ && !this.collapsed_) ?
|
||||
this.collapseLabel_ : this.label_;
|
||||
const button = document.createElement('button');
|
||||
button.setAttribute('type', 'button');
|
||||
button.title = tipLabel;
|
||||
button.appendChild(activeLabel);
|
||||
|
||||
listen(button, EventType.CLICK, this.handleClick_, this);
|
||||
|
||||
const cssClasses = className + ' ' + CLASS_UNSELECTABLE + ' ' + CLASS_CONTROL +
|
||||
(this.collapsed_ && this.collapsible_ ? ' ' + CLASS_COLLAPSED : '') +
|
||||
(this.collapsible_ ? '' : ' ol-uncollapsible');
|
||||
const element = this.element;
|
||||
element.className = cssClasses;
|
||||
element.appendChild(this.ulElement_);
|
||||
element.appendChild(button);
|
||||
|
||||
/**
|
||||
* A list of currently rendered resolutions.
|
||||
* @type {Array.<string>}
|
||||
* @private
|
||||
*/
|
||||
this.renderedAttributions_ = [];
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.renderedVisible_ = true;
|
||||
|
||||
}
|
||||
|
||||
|
||||
const activeLabel = (this.collapsible_ && !this.collapsed_) ?
|
||||
this.collapseLabel_ : this.label_;
|
||||
const button = document.createElement('button');
|
||||
button.setAttribute('type', 'button');
|
||||
button.title = tipLabel;
|
||||
button.appendChild(activeLabel);
|
||||
|
||||
listen(button, EventType.CLICK, this.handleClick_, this);
|
||||
|
||||
const cssClasses = className + ' ' + CLASS_UNSELECTABLE + ' ' + CLASS_CONTROL +
|
||||
(this.collapsed_ && this.collapsible_ ? ' ' + CLASS_COLLAPSED : '') +
|
||||
(this.collapsible_ ? '' : ' ol-uncollapsible');
|
||||
const element = document.createElement('div');
|
||||
element.className = cssClasses;
|
||||
element.appendChild(this.ulElement_);
|
||||
element.appendChild(button);
|
||||
|
||||
Control.call(this, {
|
||||
element: element,
|
||||
render: options.render || render,
|
||||
target: options.target
|
||||
});
|
||||
|
||||
/**
|
||||
* A list of currently rendered resolutions.
|
||||
* @type {Array.<string>}
|
||||
* Get a list of visible attributions.
|
||||
* @param {module:ol/PluggableMap~FrameState} frameState Frame state.
|
||||
* @return {Array.<string>} Attributions.
|
||||
* @private
|
||||
*/
|
||||
this.renderedAttributions_ = [];
|
||||
getSourceAttributions_(frameState) {
|
||||
/**
|
||||
* Used to determine if an attribution already exists.
|
||||
* @type {!Object.<string, boolean>}
|
||||
*/
|
||||
const lookup = {};
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.renderedVisible_ = true;
|
||||
/**
|
||||
* A list of visible attributions.
|
||||
* @type {Array.<string>}
|
||||
*/
|
||||
const visibleAttributions = [];
|
||||
|
||||
};
|
||||
const layerStatesArray = frameState.layerStatesArray;
|
||||
const resolution = frameState.viewState.resolution;
|
||||
for (let i = 0, ii = layerStatesArray.length; i < ii; ++i) {
|
||||
const layerState = layerStatesArray[i];
|
||||
if (!visibleAtResolution(layerState, resolution)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
inherits(Attribution, Control);
|
||||
const source = layerState.layer.getSource();
|
||||
if (!source) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const attributionGetter = source.getAttributions();
|
||||
if (!attributionGetter) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of visible attributions.
|
||||
* @param {module:ol/PluggableMap~FrameState} frameState Frame state.
|
||||
* @return {Array.<string>} Attributions.
|
||||
* @private
|
||||
*/
|
||||
Attribution.prototype.getSourceAttributions_ = function(frameState) {
|
||||
/**
|
||||
* Used to determine if an attribution already exists.
|
||||
* @type {!Object.<string, boolean>}
|
||||
*/
|
||||
const lookup = {};
|
||||
const attributions = attributionGetter(frameState);
|
||||
if (!attributions) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/**
|
||||
* A list of visible attributions.
|
||||
* @type {Array.<string>}
|
||||
*/
|
||||
const visibleAttributions = [];
|
||||
|
||||
const layerStatesArray = frameState.layerStatesArray;
|
||||
const resolution = frameState.viewState.resolution;
|
||||
for (let i = 0, ii = layerStatesArray.length; i < ii; ++i) {
|
||||
const layerState = layerStatesArray[i];
|
||||
if (!visibleAtResolution(layerState, resolution)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const source = layerState.layer.getSource();
|
||||
if (!source) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const attributionGetter = source.getAttributions();
|
||||
if (!attributionGetter) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const attributions = attributionGetter(frameState);
|
||||
if (!attributions) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (Array.isArray(attributions)) {
|
||||
for (let j = 0, jj = attributions.length; j < jj; ++j) {
|
||||
if (!(attributions[j] in lookup)) {
|
||||
visibleAttributions.push(attributions[j]);
|
||||
lookup[attributions[j]] = true;
|
||||
if (Array.isArray(attributions)) {
|
||||
for (let j = 0, jj = attributions.length; j < jj; ++j) {
|
||||
if (!(attributions[j] in lookup)) {
|
||||
visibleAttributions.push(attributions[j]);
|
||||
lookup[attributions[j]] = true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (!(attributions in lookup)) {
|
||||
visibleAttributions.push(attributions);
|
||||
lookup[attributions] = true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (!(attributions in lookup)) {
|
||||
visibleAttributions.push(attributions);
|
||||
lookup[attributions] = true;
|
||||
}
|
||||
return visibleAttributions;
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {?module:ol/PluggableMap~FrameState} frameState Frame state.
|
||||
*/
|
||||
updateElement_(frameState) {
|
||||
if (!frameState) {
|
||||
if (this.renderedVisible_) {
|
||||
this.element.style.display = 'none';
|
||||
this.renderedVisible_ = false;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
const attributions = this.getSourceAttributions_(frameState);
|
||||
|
||||
const visible = attributions.length > 0;
|
||||
if (this.renderedVisible_ != visible) {
|
||||
this.element.style.display = visible ? '' : 'none';
|
||||
this.renderedVisible_ = visible;
|
||||
}
|
||||
|
||||
if (equals(attributions, this.renderedAttributions_)) {
|
||||
return;
|
||||
}
|
||||
|
||||
removeChildren(this.ulElement_);
|
||||
|
||||
// append the attributions
|
||||
for (let i = 0, ii = attributions.length; i < ii; ++i) {
|
||||
const element = document.createElement('LI');
|
||||
element.innerHTML = attributions[i];
|
||||
this.ulElement_.appendChild(element);
|
||||
}
|
||||
|
||||
this.renderedAttributions_ = attributions;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {MouseEvent} event The event to handle
|
||||
* @private
|
||||
*/
|
||||
handleClick_(event) {
|
||||
event.preventDefault();
|
||||
this.handleToggle_();
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
handleToggle_() {
|
||||
this.element.classList.toggle(CLASS_COLLAPSED);
|
||||
if (this.collapsed_) {
|
||||
replaceNode(this.collapseLabel_, this.label_);
|
||||
} else {
|
||||
replaceNode(this.label_, this.collapseLabel_);
|
||||
}
|
||||
this.collapsed_ = !this.collapsed_;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return `true` if the attribution is collapsible, `false` otherwise.
|
||||
* @return {boolean} True if the widget is collapsible.
|
||||
* @api
|
||||
*/
|
||||
getCollapsible() {
|
||||
return this.collapsible_;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether the attribution should be collapsible.
|
||||
* @param {boolean} collapsible True if the widget is collapsible.
|
||||
* @api
|
||||
*/
|
||||
setCollapsible(collapsible) {
|
||||
if (this.collapsible_ === collapsible) {
|
||||
return;
|
||||
}
|
||||
this.collapsible_ = collapsible;
|
||||
this.element.classList.toggle('ol-uncollapsible');
|
||||
if (!collapsible && this.collapsed_) {
|
||||
this.handleToggle_();
|
||||
}
|
||||
}
|
||||
return visibleAttributions;
|
||||
};
|
||||
|
||||
/**
|
||||
* Collapse or expand the attribution according to the passed parameter. Will
|
||||
* not do anything if the attribution isn't collapsible or if the current
|
||||
* collapsed state is already the one requested.
|
||||
* @param {boolean} collapsed True if the widget is collapsed.
|
||||
* @api
|
||||
*/
|
||||
setCollapsed(collapsed) {
|
||||
if (!this.collapsible_ || this.collapsed_ === collapsed) {
|
||||
return;
|
||||
}
|
||||
this.handleToggle_();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return `true` when the attribution is currently collapsed or `false`
|
||||
* otherwise.
|
||||
* @return {boolean} True if the widget is collapsed.
|
||||
* @api
|
||||
*/
|
||||
getCollapsed() {
|
||||
return this.collapsed_;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
@@ -217,117 +324,4 @@ export function render(mapEvent) {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {?module:ol/PluggableMap~FrameState} frameState Frame state.
|
||||
*/
|
||||
Attribution.prototype.updateElement_ = function(frameState) {
|
||||
if (!frameState) {
|
||||
if (this.renderedVisible_) {
|
||||
this.element.style.display = 'none';
|
||||
this.renderedVisible_ = false;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
const attributions = this.getSourceAttributions_(frameState);
|
||||
|
||||
const visible = attributions.length > 0;
|
||||
if (this.renderedVisible_ != visible) {
|
||||
this.element.style.display = visible ? '' : 'none';
|
||||
this.renderedVisible_ = visible;
|
||||
}
|
||||
|
||||
if (equals(attributions, this.renderedAttributions_)) {
|
||||
return;
|
||||
}
|
||||
|
||||
removeChildren(this.ulElement_);
|
||||
|
||||
// append the attributions
|
||||
for (let i = 0, ii = attributions.length; i < ii; ++i) {
|
||||
const element = document.createElement('LI');
|
||||
element.innerHTML = attributions[i];
|
||||
this.ulElement_.appendChild(element);
|
||||
}
|
||||
|
||||
this.renderedAttributions_ = attributions;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {MouseEvent} event The event to handle
|
||||
* @private
|
||||
*/
|
||||
Attribution.prototype.handleClick_ = function(event) {
|
||||
event.preventDefault();
|
||||
this.handleToggle_();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
Attribution.prototype.handleToggle_ = function() {
|
||||
this.element.classList.toggle(CLASS_COLLAPSED);
|
||||
if (this.collapsed_) {
|
||||
replaceNode(this.collapseLabel_, this.label_);
|
||||
} else {
|
||||
replaceNode(this.label_, this.collapseLabel_);
|
||||
}
|
||||
this.collapsed_ = !this.collapsed_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Return `true` if the attribution is collapsible, `false` otherwise.
|
||||
* @return {boolean} True if the widget is collapsible.
|
||||
* @api
|
||||
*/
|
||||
Attribution.prototype.getCollapsible = function() {
|
||||
return this.collapsible_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Set whether the attribution should be collapsible.
|
||||
* @param {boolean} collapsible True if the widget is collapsible.
|
||||
* @api
|
||||
*/
|
||||
Attribution.prototype.setCollapsible = function(collapsible) {
|
||||
if (this.collapsible_ === collapsible) {
|
||||
return;
|
||||
}
|
||||
this.collapsible_ = collapsible;
|
||||
this.element.classList.toggle('ol-uncollapsible');
|
||||
if (!collapsible && this.collapsed_) {
|
||||
this.handleToggle_();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Collapse or expand the attribution according to the passed parameter. Will
|
||||
* not do anything if the attribution isn't collapsible or if the current
|
||||
* collapsed state is already the one requested.
|
||||
* @param {boolean} collapsed True if the widget is collapsed.
|
||||
* @api
|
||||
*/
|
||||
Attribution.prototype.setCollapsed = function(collapsed) {
|
||||
if (!this.collapsible_ || this.collapsed_ === collapsed) {
|
||||
return;
|
||||
}
|
||||
this.handleToggle_();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Return `true` when the attribution is currently collapsed or `false`
|
||||
* otherwise.
|
||||
* @return {boolean} True if the widget is collapsed.
|
||||
* @api
|
||||
*/
|
||||
Attribution.prototype.getCollapsed = function() {
|
||||
return this.collapsed_;
|
||||
};
|
||||
export default Attribution;
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
/**
|
||||
* @module ol/control/Control
|
||||
*/
|
||||
import {inherits} from '../util.js';
|
||||
import {UNDEFINED} from '../functions.js';
|
||||
import MapEventType from '../MapEventType.js';
|
||||
import BaseObject from '../Object.js';
|
||||
@@ -44,113 +43,112 @@ import {listen, unlistenByKey} from '../events.js';
|
||||
* You can also extend this base for your own control class. See
|
||||
* examples/custom-controls for an example of how to do this.
|
||||
*
|
||||
* @constructor
|
||||
* @extends {module:ol/Object}
|
||||
* @param {module:ol/control/Control~Options} options Control options.
|
||||
* @api
|
||||
*/
|
||||
const Control = function(options) {
|
||||
|
||||
BaseObject.call(this);
|
||||
class Control extends BaseObject {
|
||||
|
||||
/**
|
||||
* @protected
|
||||
* @type {Element}
|
||||
* @param {module:ol/control/Control~Options} options Control options.
|
||||
*/
|
||||
this.element = options.element ? options.element : null;
|
||||
constructor(options) {
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {Element}
|
||||
*/
|
||||
this.target_ = null;
|
||||
super();
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {module:ol/PluggableMap}
|
||||
*/
|
||||
this.map_ = null;
|
||||
/**
|
||||
* @protected
|
||||
* @type {Element}
|
||||
*/
|
||||
this.element = options.element ? options.element : null;
|
||||
|
||||
/**
|
||||
* @protected
|
||||
* @type {!Array.<module:ol/events~EventsKey>}
|
||||
*/
|
||||
this.listenerKeys = [];
|
||||
/**
|
||||
* @private
|
||||
* @type {Element}
|
||||
*/
|
||||
this.target_ = null;
|
||||
|
||||
/**
|
||||
* @type {function(module:ol/MapEvent)}
|
||||
*/
|
||||
this.render = options.render ? options.render : UNDEFINED;
|
||||
/**
|
||||
* @private
|
||||
* @type {module:ol/PluggableMap}
|
||||
*/
|
||||
this.map_ = null;
|
||||
|
||||
if (options.target) {
|
||||
this.setTarget(options.target);
|
||||
}
|
||||
/**
|
||||
* @protected
|
||||
* @type {!Array.<module:ol/events~EventsKey>}
|
||||
*/
|
||||
this.listenerKeys = [];
|
||||
|
||||
};
|
||||
/**
|
||||
* @type {function(module:ol/MapEvent)}
|
||||
*/
|
||||
this.render = options.render ? options.render : UNDEFINED;
|
||||
|
||||
inherits(Control, BaseObject);
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
Control.prototype.disposeInternal = function() {
|
||||
removeNode(this.element);
|
||||
BaseObject.prototype.disposeInternal.call(this);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get the map associated with this control.
|
||||
* @return {module:ol/PluggableMap} Map.
|
||||
* @api
|
||||
*/
|
||||
Control.prototype.getMap = function() {
|
||||
return this.map_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Remove the control from its current map and attach it to the new map.
|
||||
* Subclasses may set up event handlers to get notified about changes to
|
||||
* the map here.
|
||||
* @param {module:ol/PluggableMap} map Map.
|
||||
* @api
|
||||
*/
|
||||
Control.prototype.setMap = function(map) {
|
||||
if (this.map_) {
|
||||
removeNode(this.element);
|
||||
}
|
||||
for (let i = 0, ii = this.listenerKeys.length; i < ii; ++i) {
|
||||
unlistenByKey(this.listenerKeys[i]);
|
||||
}
|
||||
this.listenerKeys.length = 0;
|
||||
this.map_ = map;
|
||||
if (this.map_) {
|
||||
const target = this.target_ ?
|
||||
this.target_ : map.getOverlayContainerStopEvent();
|
||||
target.appendChild(this.element);
|
||||
if (this.render !== UNDEFINED) {
|
||||
this.listenerKeys.push(listen(map,
|
||||
MapEventType.POSTRENDER, this.render, this));
|
||||
if (options.target) {
|
||||
this.setTarget(options.target);
|
||||
}
|
||||
map.render();
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
disposeInternal() {
|
||||
removeNode(this.element);
|
||||
super.disposeInternal();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the map associated with this control.
|
||||
* @return {module:ol/PluggableMap} Map.
|
||||
* @api
|
||||
*/
|
||||
getMap() {
|
||||
return this.map_;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the control from its current map and attach it to the new map.
|
||||
* Subclasses may set up event handlers to get notified about changes to
|
||||
* the map here.
|
||||
* @param {module:ol/PluggableMap} map Map.
|
||||
* @api
|
||||
*/
|
||||
setMap(map) {
|
||||
if (this.map_) {
|
||||
removeNode(this.element);
|
||||
}
|
||||
for (let i = 0, ii = this.listenerKeys.length; i < ii; ++i) {
|
||||
unlistenByKey(this.listenerKeys[i]);
|
||||
}
|
||||
this.listenerKeys.length = 0;
|
||||
this.map_ = map;
|
||||
if (this.map_) {
|
||||
const target = this.target_ ?
|
||||
this.target_ : map.getOverlayContainerStopEvent();
|
||||
target.appendChild(this.element);
|
||||
if (this.render !== UNDEFINED) {
|
||||
this.listenerKeys.push(listen(map,
|
||||
MapEventType.POSTRENDER, this.render, this));
|
||||
}
|
||||
map.render();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This function is used to set a target element for the control. It has no
|
||||
* effect if it is called after the control has been added to the map (i.e.
|
||||
* after `setMap` is called on the control). If no `target` is set in the
|
||||
* options passed to the control constructor and if `setTarget` is not called
|
||||
* then the control is added to the map's overlay container.
|
||||
* @param {Element|string} target Target.
|
||||
* @api
|
||||
*/
|
||||
setTarget(target) {
|
||||
this.target_ = typeof target === 'string' ?
|
||||
document.getElementById(target) :
|
||||
target;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This function is used to set a target element for the control. It has no
|
||||
* effect if it is called after the control has been added to the map (i.e.
|
||||
* after `setMap` is called on the control). If no `target` is set in the
|
||||
* options passed to the control constructor and if `setTarget` is not called
|
||||
* then the control is added to the map's overlay container.
|
||||
* @param {Element|string} target Target.
|
||||
* @api
|
||||
*/
|
||||
Control.prototype.setTarget = function(target) {
|
||||
this.target_ = typeof target === 'string' ?
|
||||
document.getElementById(target) :
|
||||
target;
|
||||
};
|
||||
export default Control;
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
/**
|
||||
* @module ol/control/FullScreen
|
||||
*/
|
||||
import {inherits} from '../util.js';
|
||||
import Control from '../control/Control.js';
|
||||
import {CLASS_CONTROL, CLASS_UNSELECTABLE, CLASS_UNSUPPORTED} from '../css.js';
|
||||
import {replaceNode} from '../dom.js';
|
||||
@@ -61,154 +60,151 @@ const getChangeType = (function() {
|
||||
* The [Fullscreen API](http://www.w3.org/TR/fullscreen/) is used to
|
||||
* toggle the map in full screen mode.
|
||||
*
|
||||
*
|
||||
* @constructor
|
||||
* @extends {module:ol/control/Control}
|
||||
* @param {module:ol/control/FullScreen~Options=} opt_options Options.
|
||||
* @api
|
||||
*/
|
||||
const FullScreen = function(opt_options) {
|
||||
|
||||
const options = opt_options ? opt_options : {};
|
||||
class FullScreen extends Control {
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {string}
|
||||
* @param {module:ol/control/FullScreen~Options=} opt_options Options.
|
||||
*/
|
||||
this.cssClassName_ = options.className !== undefined ? options.className :
|
||||
'ol-full-screen';
|
||||
constructor(opt_options) {
|
||||
|
||||
const label = options.label !== undefined ? options.label : '\u2922';
|
||||
const options = opt_options ? opt_options : {};
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {Element}
|
||||
*/
|
||||
this.labelNode_ = typeof label === 'string' ?
|
||||
document.createTextNode(label) : label;
|
||||
super({
|
||||
element: document.createElement('div'),
|
||||
target: options.target
|
||||
});
|
||||
|
||||
const labelActive = options.labelActive !== undefined ? options.labelActive : '\u00d7';
|
||||
/**
|
||||
* @private
|
||||
* @type {string}
|
||||
*/
|
||||
this.cssClassName_ = options.className !== undefined ? options.className :
|
||||
'ol-full-screen';
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {Element}
|
||||
*/
|
||||
this.labelActiveNode_ = typeof labelActive === 'string' ?
|
||||
document.createTextNode(labelActive) : labelActive;
|
||||
const label = options.label !== undefined ? options.label : '\u2922';
|
||||
|
||||
const tipLabel = options.tipLabel ? options.tipLabel : 'Toggle full-screen';
|
||||
const button = document.createElement('button');
|
||||
button.className = this.cssClassName_ + '-' + isFullScreen();
|
||||
button.setAttribute('type', 'button');
|
||||
button.title = tipLabel;
|
||||
button.appendChild(this.labelNode_);
|
||||
/**
|
||||
* @private
|
||||
* @type {Element}
|
||||
*/
|
||||
this.labelNode_ = typeof label === 'string' ?
|
||||
document.createTextNode(label) : label;
|
||||
|
||||
listen(button, EventType.CLICK,
|
||||
this.handleClick_, this);
|
||||
const labelActive = options.labelActive !== undefined ? options.labelActive : '\u00d7';
|
||||
|
||||
const cssClasses = this.cssClassName_ + ' ' + CLASS_UNSELECTABLE +
|
||||
' ' + CLASS_CONTROL + ' ' +
|
||||
(!isFullScreenSupported() ? CLASS_UNSUPPORTED : '');
|
||||
const element = document.createElement('div');
|
||||
element.className = cssClasses;
|
||||
element.appendChild(button);
|
||||
/**
|
||||
* @private
|
||||
* @type {Element}
|
||||
*/
|
||||
this.labelActiveNode_ = typeof labelActive === 'string' ?
|
||||
document.createTextNode(labelActive) : labelActive;
|
||||
|
||||
Control.call(this, {
|
||||
element: element,
|
||||
target: options.target
|
||||
});
|
||||
const tipLabel = options.tipLabel ? options.tipLabel : 'Toggle full-screen';
|
||||
const button = document.createElement('button');
|
||||
button.className = this.cssClassName_ + '-' + isFullScreen();
|
||||
button.setAttribute('type', 'button');
|
||||
button.title = tipLabel;
|
||||
button.appendChild(this.labelNode_);
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.keys_ = options.keys !== undefined ? options.keys : false;
|
||||
listen(button, EventType.CLICK,
|
||||
this.handleClick_, this);
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {Element|string|undefined}
|
||||
*/
|
||||
this.source_ = options.source;
|
||||
const cssClasses = this.cssClassName_ + ' ' + CLASS_UNSELECTABLE +
|
||||
' ' + CLASS_CONTROL + ' ' +
|
||||
(!isFullScreenSupported() ? CLASS_UNSUPPORTED : '');
|
||||
const element = this.element;
|
||||
element.className = cssClasses;
|
||||
element.appendChild(button);
|
||||
|
||||
};
|
||||
/**
|
||||
* @private
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.keys_ = options.keys !== undefined ? options.keys : false;
|
||||
|
||||
inherits(FullScreen, Control);
|
||||
/**
|
||||
* @private
|
||||
* @type {Element|string|undefined}
|
||||
*/
|
||||
this.source_ = options.source;
|
||||
|
||||
|
||||
/**
|
||||
* @param {MouseEvent} event The event to handle
|
||||
* @private
|
||||
*/
|
||||
FullScreen.prototype.handleClick_ = function(event) {
|
||||
event.preventDefault();
|
||||
this.handleFullScreen_();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
FullScreen.prototype.handleFullScreen_ = function() {
|
||||
if (!isFullScreenSupported()) {
|
||||
return;
|
||||
}
|
||||
const map = this.getMap();
|
||||
if (!map) {
|
||||
return;
|
||||
|
||||
/**
|
||||
* @param {MouseEvent} event The event to handle
|
||||
* @private
|
||||
*/
|
||||
handleClick_(event) {
|
||||
event.preventDefault();
|
||||
this.handleFullScreen_();
|
||||
}
|
||||
if (isFullScreen()) {
|
||||
exitFullScreen();
|
||||
} else {
|
||||
let element;
|
||||
if (this.source_) {
|
||||
element = typeof this.source_ === 'string' ?
|
||||
document.getElementById(this.source_) :
|
||||
this.source_;
|
||||
} else {
|
||||
element = map.getTargetElement();
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
handleFullScreen_() {
|
||||
if (!isFullScreenSupported()) {
|
||||
return;
|
||||
}
|
||||
if (this.keys_) {
|
||||
requestFullScreenWithKeys(element);
|
||||
|
||||
const map = this.getMap();
|
||||
if (!map) {
|
||||
return;
|
||||
}
|
||||
if (isFullScreen()) {
|
||||
exitFullScreen();
|
||||
} else {
|
||||
requestFullScreen(element);
|
||||
let element;
|
||||
if (this.source_) {
|
||||
element = typeof this.source_ === 'string' ?
|
||||
document.getElementById(this.source_) :
|
||||
this.source_;
|
||||
} else {
|
||||
element = map.getTargetElement();
|
||||
}
|
||||
if (this.keys_) {
|
||||
requestFullScreenWithKeys(element);
|
||||
|
||||
} else {
|
||||
requestFullScreen(element);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
FullScreen.prototype.handleFullScreenChange_ = function() {
|
||||
const button = this.element.firstElementChild;
|
||||
const map = this.getMap();
|
||||
if (isFullScreen()) {
|
||||
button.className = this.cssClassName_ + '-true';
|
||||
replaceNode(this.labelActiveNode_, this.labelNode_);
|
||||
} else {
|
||||
button.className = this.cssClassName_ + '-false';
|
||||
replaceNode(this.labelNode_, this.labelActiveNode_);
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
handleFullScreenChange_() {
|
||||
const button = this.element.firstElementChild;
|
||||
const map = this.getMap();
|
||||
if (isFullScreen()) {
|
||||
button.className = this.cssClassName_ + '-true';
|
||||
replaceNode(this.labelActiveNode_, this.labelNode_);
|
||||
} else {
|
||||
button.className = this.cssClassName_ + '-false';
|
||||
replaceNode(this.labelNode_, this.labelActiveNode_);
|
||||
}
|
||||
if (map) {
|
||||
map.updateSize();
|
||||
}
|
||||
}
|
||||
if (map) {
|
||||
map.updateSize();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @api
|
||||
*/
|
||||
FullScreen.prototype.setMap = function(map) {
|
||||
Control.prototype.setMap.call(this, map);
|
||||
if (map) {
|
||||
this.listenerKeys.push(listen(document,
|
||||
getChangeType(),
|
||||
this.handleFullScreenChange_, this)
|
||||
);
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @api
|
||||
*/
|
||||
setMap(map) {
|
||||
super.setMap(map);
|
||||
if (map) {
|
||||
this.listenerKeys.push(listen(document,
|
||||
getChangeType(),
|
||||
this.handleFullScreenChange_, this)
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return {boolean} Fullscreen is supported by the current platform.
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
/**
|
||||
* @module ol/control/MousePosition
|
||||
*/
|
||||
|
||||
import {inherits} from '../util.js';
|
||||
import {listen} from '../events.js';
|
||||
import EventType from '../events/EventType.js';
|
||||
import {getChangeEventType} from '../Object.js';
|
||||
@@ -46,75 +44,203 @@ const COORDINATE_FORMAT = 'coordinateFormat';
|
||||
* By default the control is shown in the top right corner of the map, but this
|
||||
* can be changed by using the css selector `.ol-mouse-position`.
|
||||
*
|
||||
* @constructor
|
||||
* @extends {module:ol/control/Control}
|
||||
* @param {module:ol/control/MousePosition~Options=} opt_options Mouse position
|
||||
* options.
|
||||
* @api
|
||||
*/
|
||||
const MousePosition = function(opt_options) {
|
||||
class MousePosition extends Control {
|
||||
|
||||
const options = opt_options ? opt_options : {};
|
||||
/**
|
||||
* @param {module:ol/control/MousePosition~Options=} opt_options Mouse position options.
|
||||
*/
|
||||
constructor(opt_options) {
|
||||
|
||||
const element = document.createElement('DIV');
|
||||
element.className = options.className !== undefined ? options.className : 'ol-mouse-position';
|
||||
const options = opt_options ? opt_options : {};
|
||||
|
||||
Control.call(this, {
|
||||
element: element,
|
||||
render: options.render || render,
|
||||
target: options.target
|
||||
});
|
||||
const element = document.createElement('DIV');
|
||||
element.className = options.className !== undefined ? options.className : 'ol-mouse-position';
|
||||
|
||||
listen(this,
|
||||
getChangeEventType(PROJECTION),
|
||||
this.handleProjectionChanged_, this);
|
||||
super({
|
||||
element: element,
|
||||
render: options.render || render,
|
||||
target: options.target
|
||||
});
|
||||
|
||||
listen(this,
|
||||
getChangeEventType(PROJECTION),
|
||||
this.handleProjectionChanged_, this);
|
||||
|
||||
if (options.coordinateFormat) {
|
||||
this.setCoordinateFormat(options.coordinateFormat);
|
||||
}
|
||||
if (options.projection) {
|
||||
this.setProjection(options.projection);
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {string}
|
||||
*/
|
||||
this.undefinedHTML_ = 'undefinedHTML' in options ? options.undefinedHTML : ' ';
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.renderOnMouseOut_ = !!this.undefinedHTML_;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {string}
|
||||
*/
|
||||
this.renderedHTML_ = element.innerHTML;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {module:ol/proj/Projection}
|
||||
*/
|
||||
this.mapProjection_ = null;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {?module:ol/proj~TransformFunction}
|
||||
*/
|
||||
this.transform_ = null;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {module:ol~Pixel}
|
||||
*/
|
||||
this.lastMouseMovePixel_ = null;
|
||||
|
||||
if (options.coordinateFormat) {
|
||||
this.setCoordinateFormat(options.coordinateFormat);
|
||||
}
|
||||
if (options.projection) {
|
||||
this.setProjection(options.projection);
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {string}
|
||||
*/
|
||||
this.undefinedHTML_ = 'undefinedHTML' in options ? options.undefinedHTML : ' ';
|
||||
handleProjectionChanged_() {
|
||||
this.transform_ = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {boolean}
|
||||
* Return the coordinate format type used to render the current position or
|
||||
* undefined.
|
||||
* @return {module:ol/coordinate~CoordinateFormat|undefined} The format to render the current
|
||||
* position in.
|
||||
* @observable
|
||||
* @api
|
||||
*/
|
||||
this.renderOnMouseOut_ = !!this.undefinedHTML_;
|
||||
getCoordinateFormat() {
|
||||
return (
|
||||
/** @type {module:ol/coordinate~CoordinateFormat|undefined} */ (this.get(COORDINATE_FORMAT))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {string}
|
||||
* Return the projection that is used to report the mouse position.
|
||||
* @return {module:ol/proj/Projection|undefined} The projection to report mouse
|
||||
* position in.
|
||||
* @observable
|
||||
* @api
|
||||
*/
|
||||
this.renderedHTML_ = element.innerHTML;
|
||||
getProjection() {
|
||||
return (
|
||||
/** @type {module:ol/proj/Projection|undefined} */ (this.get(PROJECTION))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {module:ol/proj/Projection}
|
||||
* @param {Event} event Browser event.
|
||||
* @protected
|
||||
*/
|
||||
this.mapProjection_ = null;
|
||||
handleMouseMove(event) {
|
||||
const map = this.getMap();
|
||||
this.lastMouseMovePixel_ = map.getEventPixel(event);
|
||||
this.updateHTML_(this.lastMouseMovePixel_);
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {?module:ol/proj~TransformFunction}
|
||||
* @param {Event} event Browser event.
|
||||
* @protected
|
||||
*/
|
||||
this.transform_ = null;
|
||||
handleMouseOut(event) {
|
||||
this.updateHTML_(null);
|
||||
this.lastMouseMovePixel_ = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {module:ol~Pixel}
|
||||
* @inheritDoc
|
||||
* @api
|
||||
*/
|
||||
this.lastMouseMovePixel_ = null;
|
||||
setMap(map) {
|
||||
super.setMap(map);
|
||||
if (map) {
|
||||
const viewport = map.getViewport();
|
||||
this.listenerKeys.push(
|
||||
listen(viewport, EventType.MOUSEMOVE, this.handleMouseMove, this)
|
||||
);
|
||||
if (this.renderOnMouseOut_) {
|
||||
this.listenerKeys.push(
|
||||
listen(viewport, EventType.MOUSEOUT, this.handleMouseOut, this)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
/**
|
||||
* Set the coordinate format type used to render the current position.
|
||||
* @param {module:ol/coordinate~CoordinateFormat} format The format to render the current
|
||||
* position in.
|
||||
* @observable
|
||||
* @api
|
||||
*/
|
||||
setCoordinateFormat(format) {
|
||||
this.set(COORDINATE_FORMAT, format);
|
||||
}
|
||||
|
||||
inherits(MousePosition, Control);
|
||||
/**
|
||||
* Set the projection that is used to report the mouse position.
|
||||
* @param {module:ol/proj~ProjectionLike} projection The projection to report mouse
|
||||
* position in.
|
||||
* @observable
|
||||
* @api
|
||||
*/
|
||||
setProjection(projection) {
|
||||
this.set(PROJECTION, getProjection(projection));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {?module:ol~Pixel} pixel Pixel.
|
||||
* @private
|
||||
*/
|
||||
updateHTML_(pixel) {
|
||||
let html = this.undefinedHTML_;
|
||||
if (pixel && this.mapProjection_) {
|
||||
if (!this.transform_) {
|
||||
const projection = this.getProjection();
|
||||
if (projection) {
|
||||
this.transform_ = getTransformFromProjections(
|
||||
this.mapProjection_, projection);
|
||||
} else {
|
||||
this.transform_ = identityTransform;
|
||||
}
|
||||
}
|
||||
const map = this.getMap();
|
||||
const coordinate = map.getCoordinateFromPixel(pixel);
|
||||
if (coordinate) {
|
||||
this.transform_(coordinate, coordinate);
|
||||
const coordinateFormat = this.getCoordinateFormat();
|
||||
if (coordinateFormat) {
|
||||
html = coordinateFormat(coordinate);
|
||||
} else {
|
||||
html = coordinate.toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!this.renderedHTML_ || html !== this.renderedHTML_) {
|
||||
this.element.innerHTML = html;
|
||||
this.renderedHTML_ = html;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
@@ -137,141 +263,4 @@ export function render(mapEvent) {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
MousePosition.prototype.handleProjectionChanged_ = function() {
|
||||
this.transform_ = null;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Return the coordinate format type used to render the current position or
|
||||
* undefined.
|
||||
* @return {module:ol/coordinate~CoordinateFormat|undefined} The format to render the current
|
||||
* position in.
|
||||
* @observable
|
||||
* @api
|
||||
*/
|
||||
MousePosition.prototype.getCoordinateFormat = function() {
|
||||
return (
|
||||
/** @type {module:ol/coordinate~CoordinateFormat|undefined} */ (this.get(COORDINATE_FORMAT))
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Return the projection that is used to report the mouse position.
|
||||
* @return {module:ol/proj/Projection|undefined} The projection to report mouse
|
||||
* position in.
|
||||
* @observable
|
||||
* @api
|
||||
*/
|
||||
MousePosition.prototype.getProjection = function() {
|
||||
return (
|
||||
/** @type {module:ol/proj/Projection|undefined} */ (this.get(PROJECTION))
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {Event} event Browser event.
|
||||
* @protected
|
||||
*/
|
||||
MousePosition.prototype.handleMouseMove = function(event) {
|
||||
const map = this.getMap();
|
||||
this.lastMouseMovePixel_ = map.getEventPixel(event);
|
||||
this.updateHTML_(this.lastMouseMovePixel_);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {Event} event Browser event.
|
||||
* @protected
|
||||
*/
|
||||
MousePosition.prototype.handleMouseOut = function(event) {
|
||||
this.updateHTML_(null);
|
||||
this.lastMouseMovePixel_ = null;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @api
|
||||
*/
|
||||
MousePosition.prototype.setMap = function(map) {
|
||||
Control.prototype.setMap.call(this, map);
|
||||
if (map) {
|
||||
const viewport = map.getViewport();
|
||||
this.listenerKeys.push(
|
||||
listen(viewport, EventType.MOUSEMOVE, this.handleMouseMove, this)
|
||||
);
|
||||
if (this.renderOnMouseOut_) {
|
||||
this.listenerKeys.push(
|
||||
listen(viewport, EventType.MOUSEOUT, this.handleMouseOut, this)
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Set the coordinate format type used to render the current position.
|
||||
* @param {module:ol/coordinate~CoordinateFormat} format The format to render the current
|
||||
* position in.
|
||||
* @observable
|
||||
* @api
|
||||
*/
|
||||
MousePosition.prototype.setCoordinateFormat = function(format) {
|
||||
this.set(COORDINATE_FORMAT, format);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Set the projection that is used to report the mouse position.
|
||||
* @param {module:ol/proj~ProjectionLike} projection The projection to report mouse
|
||||
* position in.
|
||||
* @observable
|
||||
* @api
|
||||
*/
|
||||
MousePosition.prototype.setProjection = function(projection) {
|
||||
this.set(PROJECTION, getProjection(projection));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {?module:ol~Pixel} pixel Pixel.
|
||||
* @private
|
||||
*/
|
||||
MousePosition.prototype.updateHTML_ = function(pixel) {
|
||||
let html = this.undefinedHTML_;
|
||||
if (pixel && this.mapProjection_) {
|
||||
if (!this.transform_) {
|
||||
const projection = this.getProjection();
|
||||
if (projection) {
|
||||
this.transform_ = getTransformFromProjections(
|
||||
this.mapProjection_, projection);
|
||||
} else {
|
||||
this.transform_ = identityTransform;
|
||||
}
|
||||
}
|
||||
const map = this.getMap();
|
||||
const coordinate = map.getCoordinateFromPixel(pixel);
|
||||
if (coordinate) {
|
||||
this.transform_(coordinate, coordinate);
|
||||
const coordinateFormat = this.getCoordinateFormat();
|
||||
if (coordinateFormat) {
|
||||
html = coordinateFormat(coordinate);
|
||||
} else {
|
||||
html = coordinate.toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!this.renderedHTML_ || html !== this.renderedHTML_) {
|
||||
this.element.innerHTML = html;
|
||||
this.renderedHTML_ = html;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
export default MousePosition;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,13 +1,11 @@
|
||||
/**
|
||||
* @module ol/control/Rotate
|
||||
*/
|
||||
|
||||
import Control from '../control/Control.js';
|
||||
import {CLASS_CONTROL, CLASS_HIDDEN, CLASS_UNSELECTABLE} from '../css.js';
|
||||
import {easeOut} from '../easing.js';
|
||||
import {listen} from '../events.js';
|
||||
import EventType from '../events/EventType.js';
|
||||
import {inherits} from '../util.js';
|
||||
|
||||
|
||||
/**
|
||||
@@ -33,122 +31,120 @@ import {inherits} from '../util.js';
|
||||
* To style this control use css selector `.ol-rotate`. A `.ol-hidden` css
|
||||
* selector is added to the button when the rotation is 0.
|
||||
*
|
||||
* @constructor
|
||||
* @extends {module:ol/control/Control}
|
||||
* @param {module:ol/control/Rotate~Options=} opt_options Rotate options.
|
||||
* @api
|
||||
*/
|
||||
const Rotate = function(opt_options) {
|
||||
|
||||
const options = opt_options ? opt_options : {};
|
||||
|
||||
const className = options.className !== undefined ? options.className : 'ol-rotate';
|
||||
|
||||
const label = options.label !== undefined ? options.label : '\u21E7';
|
||||
class Rotate extends Control {
|
||||
|
||||
/**
|
||||
* @type {Element}
|
||||
* @private
|
||||
* @param {module:ol/control/Rotate~Options=} opt_options Rotate options.
|
||||
*/
|
||||
this.label_ = null;
|
||||
constructor(opt_options) {
|
||||
|
||||
if (typeof label === 'string') {
|
||||
this.label_ = document.createElement('span');
|
||||
this.label_.className = 'ol-compass';
|
||||
this.label_.textContent = label;
|
||||
} else {
|
||||
this.label_ = label;
|
||||
this.label_.classList.add('ol-compass');
|
||||
}
|
||||
const options = opt_options ? opt_options : {};
|
||||
|
||||
const tipLabel = options.tipLabel ? options.tipLabel : 'Reset rotation';
|
||||
super({
|
||||
element: document.createElement('div'),
|
||||
render: options.render || render,
|
||||
target: options.target
|
||||
});
|
||||
|
||||
const button = document.createElement('button');
|
||||
button.className = className + '-reset';
|
||||
button.setAttribute('type', 'button');
|
||||
button.title = tipLabel;
|
||||
button.appendChild(this.label_);
|
||||
const className = options.className !== undefined ? options.className : 'ol-rotate';
|
||||
|
||||
listen(button, EventType.CLICK,
|
||||
Rotate.prototype.handleClick_, this);
|
||||
const label = options.label !== undefined ? options.label : '\u21E7';
|
||||
|
||||
const cssClasses = className + ' ' + CLASS_UNSELECTABLE + ' ' + CLASS_CONTROL;
|
||||
const element = document.createElement('div');
|
||||
element.className = cssClasses;
|
||||
element.appendChild(button);
|
||||
/**
|
||||
* @type {Element}
|
||||
* @private
|
||||
*/
|
||||
this.label_ = null;
|
||||
|
||||
this.callResetNorth_ = options.resetNorth ? options.resetNorth : undefined;
|
||||
|
||||
Control.call(this, {
|
||||
element: element,
|
||||
render: options.render || render,
|
||||
target: options.target
|
||||
});
|
||||
|
||||
/**
|
||||
* @type {number}
|
||||
* @private
|
||||
*/
|
||||
this.duration_ = options.duration !== undefined ? options.duration : 250;
|
||||
|
||||
/**
|
||||
* @type {boolean}
|
||||
* @private
|
||||
*/
|
||||
this.autoHide_ = options.autoHide !== undefined ? options.autoHide : true;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {number|undefined}
|
||||
*/
|
||||
this.rotation_ = undefined;
|
||||
|
||||
if (this.autoHide_) {
|
||||
this.element.classList.add(CLASS_HIDDEN);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
inherits(Rotate, Control);
|
||||
|
||||
|
||||
/**
|
||||
* @param {MouseEvent} event The event to handle
|
||||
* @private
|
||||
*/
|
||||
Rotate.prototype.handleClick_ = function(event) {
|
||||
event.preventDefault();
|
||||
if (this.callResetNorth_ !== undefined) {
|
||||
this.callResetNorth_();
|
||||
} else {
|
||||
this.resetNorth_();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
Rotate.prototype.resetNorth_ = function() {
|
||||
const map = this.getMap();
|
||||
const view = map.getView();
|
||||
if (!view) {
|
||||
// the map does not have a view, so we can't act
|
||||
// upon it
|
||||
return;
|
||||
}
|
||||
if (view.getRotation() !== undefined) {
|
||||
if (this.duration_ > 0) {
|
||||
view.animate({
|
||||
rotation: 0,
|
||||
duration: this.duration_,
|
||||
easing: easeOut
|
||||
});
|
||||
if (typeof label === 'string') {
|
||||
this.label_ = document.createElement('span');
|
||||
this.label_.className = 'ol-compass';
|
||||
this.label_.textContent = label;
|
||||
} else {
|
||||
view.setRotation(0);
|
||||
this.label_ = label;
|
||||
this.label_.classList.add('ol-compass');
|
||||
}
|
||||
|
||||
const tipLabel = options.tipLabel ? options.tipLabel : 'Reset rotation';
|
||||
|
||||
const button = document.createElement('button');
|
||||
button.className = className + '-reset';
|
||||
button.setAttribute('type', 'button');
|
||||
button.title = tipLabel;
|
||||
button.appendChild(this.label_);
|
||||
|
||||
listen(button, EventType.CLICK, this.handleClick_, this);
|
||||
|
||||
const cssClasses = className + ' ' + CLASS_UNSELECTABLE + ' ' + CLASS_CONTROL;
|
||||
const element = this.element;
|
||||
element.className = cssClasses;
|
||||
element.appendChild(button);
|
||||
|
||||
this.callResetNorth_ = options.resetNorth ? options.resetNorth : undefined;
|
||||
|
||||
/**
|
||||
* @type {number}
|
||||
* @private
|
||||
*/
|
||||
this.duration_ = options.duration !== undefined ? options.duration : 250;
|
||||
|
||||
/**
|
||||
* @type {boolean}
|
||||
* @private
|
||||
*/
|
||||
this.autoHide_ = options.autoHide !== undefined ? options.autoHide : true;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {number|undefined}
|
||||
*/
|
||||
this.rotation_ = undefined;
|
||||
|
||||
if (this.autoHide_) {
|
||||
this.element.classList.add(CLASS_HIDDEN);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {MouseEvent} event The event to handle
|
||||
* @private
|
||||
*/
|
||||
handleClick_(event) {
|
||||
event.preventDefault();
|
||||
if (this.callResetNorth_ !== undefined) {
|
||||
this.callResetNorth_();
|
||||
} else {
|
||||
this.resetNorth_();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
resetNorth_() {
|
||||
const map = this.getMap();
|
||||
const view = map.getView();
|
||||
if (!view) {
|
||||
// the map does not have a view, so we can't act
|
||||
// upon it
|
||||
return;
|
||||
}
|
||||
if (view.getRotation() !== undefined) {
|
||||
if (this.duration_ > 0) {
|
||||
view.animate({
|
||||
rotation: 0,
|
||||
duration: this.duration_,
|
||||
easing: easeOut
|
||||
});
|
||||
} else {
|
||||
view.setRotation(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
/**
|
||||
* @module ol/control/ScaleLine
|
||||
*/
|
||||
import {inherits} from '../util.js';
|
||||
import {getChangeEventType} from '../Object.js';
|
||||
import {assert} from '../asserts.js';
|
||||
import Control from '../control/Control.js';
|
||||
@@ -59,92 +58,226 @@ const LEADING_DIGITS = [1, 2, 5];
|
||||
* By default the scale line will show in the bottom left portion of the map,
|
||||
* but this can be changed by using the css selector `.ol-scale-line`.
|
||||
*
|
||||
* @constructor
|
||||
* @extends {module:ol/control/Control}
|
||||
* @param {module:ol/control/ScaleLine~Options=} opt_options Scale line options.
|
||||
* @api
|
||||
*/
|
||||
const ScaleLine = function(opt_options) {
|
||||
class ScaleLine extends Control {
|
||||
|
||||
const options = opt_options ? opt_options : {};
|
||||
/**
|
||||
* @param {module:ol/control/ScaleLine~Options=} opt_options Scale line options.
|
||||
*/
|
||||
constructor(opt_options) {
|
||||
|
||||
const className = options.className !== undefined ? options.className : 'ol-scale-line';
|
||||
const options = opt_options ? opt_options : {};
|
||||
|
||||
const className = options.className !== undefined ? options.className : 'ol-scale-line';
|
||||
|
||||
super({
|
||||
element: document.createElement('DIV'),
|
||||
render: options.render || render,
|
||||
target: options.target
|
||||
});
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {HTMLElement}
|
||||
*/
|
||||
this.innerElement_ = document.createElement('DIV');
|
||||
this.innerElement_.className = className + '-inner';
|
||||
|
||||
this.element.className = className + ' ' + CLASS_UNSELECTABLE;
|
||||
this.element.appendChild(this.innerElement_);
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {?module:ol/View~State}
|
||||
*/
|
||||
this.viewState_ = null;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {number}
|
||||
*/
|
||||
this.minWidth_ = options.minWidth !== undefined ? options.minWidth : 64;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.renderedVisible_ = false;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {number|undefined}
|
||||
*/
|
||||
this.renderedWidth_ = undefined;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {string}
|
||||
*/
|
||||
this.renderedHTML_ = '';
|
||||
|
||||
listen(
|
||||
this, getChangeEventType(UNITS_PROP),
|
||||
this.handleUnitsChanged_, this);
|
||||
|
||||
this.setUnits(/** @type {module:ol/control/ScaleLine~Units} */ (options.units) ||
|
||||
Units.METRIC);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the units to use in the scale line.
|
||||
* @return {module:ol/control/ScaleLine~Units|undefined} The units
|
||||
* to use in the scale line.
|
||||
* @observable
|
||||
* @api
|
||||
*/
|
||||
getUnits() {
|
||||
return (
|
||||
/** @type {module:ol/control/ScaleLine~Units|undefined} */ (this.get(UNITS_PROP))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {HTMLElement}
|
||||
*/
|
||||
this.innerElement_ = document.createElement('DIV');
|
||||
this.innerElement_.className = className + '-inner';
|
||||
handleUnitsChanged_() {
|
||||
this.updateElement_();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the units to use in the scale line.
|
||||
* @param {module:ol/control/ScaleLine~Units} units The units to use in the scale line.
|
||||
* @observable
|
||||
* @api
|
||||
*/
|
||||
setUnits(units) {
|
||||
this.set(UNITS_PROP, units);
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {HTMLElement}
|
||||
*/
|
||||
this.element_ = document.createElement('DIV');
|
||||
this.element_.className = className + ' ' + CLASS_UNSELECTABLE;
|
||||
this.element_.appendChild(this.innerElement_);
|
||||
updateElement_() {
|
||||
const viewState = this.viewState_;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {?module:ol/View~State}
|
||||
*/
|
||||
this.viewState_ = null;
|
||||
if (!viewState) {
|
||||
if (this.renderedVisible_) {
|
||||
this.element.style.display = 'none';
|
||||
this.renderedVisible_ = false;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {number}
|
||||
*/
|
||||
this.minWidth_ = options.minWidth !== undefined ? options.minWidth : 64;
|
||||
const center = viewState.center;
|
||||
const projection = viewState.projection;
|
||||
const units = this.getUnits();
|
||||
const pointResolutionUnits = units == Units.DEGREES ?
|
||||
ProjUnits.DEGREES :
|
||||
ProjUnits.METERS;
|
||||
let pointResolution =
|
||||
getPointResolution(projection, viewState.resolution, center, pointResolutionUnits);
|
||||
if (projection.getUnits() != ProjUnits.DEGREES && projection.getMetersPerUnit()
|
||||
&& pointResolutionUnits == ProjUnits.METERS) {
|
||||
pointResolution *= projection.getMetersPerUnit();
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.renderedVisible_ = false;
|
||||
let nominalCount = this.minWidth_ * pointResolution;
|
||||
let suffix = '';
|
||||
if (units == Units.DEGREES) {
|
||||
const metersPerDegree = METERS_PER_UNIT[ProjUnits.DEGREES];
|
||||
if (projection.getUnits() == ProjUnits.DEGREES) {
|
||||
nominalCount *= metersPerDegree;
|
||||
} else {
|
||||
pointResolution /= metersPerDegree;
|
||||
}
|
||||
if (nominalCount < metersPerDegree / 60) {
|
||||
suffix = '\u2033'; // seconds
|
||||
pointResolution *= 3600;
|
||||
} else if (nominalCount < metersPerDegree) {
|
||||
suffix = '\u2032'; // minutes
|
||||
pointResolution *= 60;
|
||||
} else {
|
||||
suffix = '\u00b0'; // degrees
|
||||
}
|
||||
} else if (units == Units.IMPERIAL) {
|
||||
if (nominalCount < 0.9144) {
|
||||
suffix = 'in';
|
||||
pointResolution /= 0.0254;
|
||||
} else if (nominalCount < 1609.344) {
|
||||
suffix = 'ft';
|
||||
pointResolution /= 0.3048;
|
||||
} else {
|
||||
suffix = 'mi';
|
||||
pointResolution /= 1609.344;
|
||||
}
|
||||
} else if (units == Units.NAUTICAL) {
|
||||
pointResolution /= 1852;
|
||||
suffix = 'nm';
|
||||
} else if (units == Units.METRIC) {
|
||||
if (nominalCount < 0.001) {
|
||||
suffix = 'μm';
|
||||
pointResolution *= 1000000;
|
||||
} else if (nominalCount < 1) {
|
||||
suffix = 'mm';
|
||||
pointResolution *= 1000;
|
||||
} else if (nominalCount < 1000) {
|
||||
suffix = 'm';
|
||||
} else {
|
||||
suffix = 'km';
|
||||
pointResolution /= 1000;
|
||||
}
|
||||
} else if (units == Units.US) {
|
||||
if (nominalCount < 0.9144) {
|
||||
suffix = 'in';
|
||||
pointResolution *= 39.37;
|
||||
} else if (nominalCount < 1609.344) {
|
||||
suffix = 'ft';
|
||||
pointResolution /= 0.30480061;
|
||||
} else {
|
||||
suffix = 'mi';
|
||||
pointResolution /= 1609.3472;
|
||||
}
|
||||
} else {
|
||||
assert(false, 33); // Invalid units
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {number|undefined}
|
||||
*/
|
||||
this.renderedWidth_ = undefined;
|
||||
let i = 3 * Math.floor(
|
||||
Math.log(this.minWidth_ * pointResolution) / Math.log(10));
|
||||
let count, width;
|
||||
while (true) {
|
||||
count = LEADING_DIGITS[((i % 3) + 3) % 3] *
|
||||
Math.pow(10, Math.floor(i / 3));
|
||||
width = Math.round(count / pointResolution);
|
||||
if (isNaN(width)) {
|
||||
this.element.style.display = 'none';
|
||||
this.renderedVisible_ = false;
|
||||
return;
|
||||
} else if (width >= this.minWidth_) {
|
||||
break;
|
||||
}
|
||||
++i;
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {string}
|
||||
*/
|
||||
this.renderedHTML_ = '';
|
||||
const html = count + ' ' + suffix;
|
||||
if (this.renderedHTML_ != html) {
|
||||
this.innerElement_.innerHTML = html;
|
||||
this.renderedHTML_ = html;
|
||||
}
|
||||
|
||||
Control.call(this, {
|
||||
element: this.element_,
|
||||
render: options.render || render,
|
||||
target: options.target
|
||||
});
|
||||
if (this.renderedWidth_ != width) {
|
||||
this.innerElement_.style.width = width + 'px';
|
||||
this.renderedWidth_ = width;
|
||||
}
|
||||
|
||||
listen(
|
||||
this, getChangeEventType(UNITS_PROP),
|
||||
this.handleUnitsChanged_, this);
|
||||
if (!this.renderedVisible_) {
|
||||
this.element.style.display = '';
|
||||
this.renderedVisible_ = true;
|
||||
}
|
||||
|
||||
this.setUnits(/** @type {module:ol/control/ScaleLine~Units} */ (options.units) ||
|
||||
Units.METRIC);
|
||||
|
||||
};
|
||||
|
||||
inherits(ScaleLine, Control);
|
||||
|
||||
|
||||
/**
|
||||
* Return the units to use in the scale line.
|
||||
* @return {module:ol/control/ScaleLine~Units|undefined} The units
|
||||
* to use in the scale line.
|
||||
* @observable
|
||||
* @api
|
||||
*/
|
||||
ScaleLine.prototype.getUnits = function() {
|
||||
return (
|
||||
/** @type {module:ol/control/ScaleLine~Units|undefined} */ (this.get(UNITS_PROP))
|
||||
);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
@@ -164,145 +297,4 @@ export function render(mapEvent) {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
ScaleLine.prototype.handleUnitsChanged_ = function() {
|
||||
this.updateElement_();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Set the units to use in the scale line.
|
||||
* @param {module:ol/control/ScaleLine~Units} units The units to use in the scale line.
|
||||
* @observable
|
||||
* @api
|
||||
*/
|
||||
ScaleLine.prototype.setUnits = function(units) {
|
||||
this.set(UNITS_PROP, units);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
ScaleLine.prototype.updateElement_ = function() {
|
||||
const viewState = this.viewState_;
|
||||
|
||||
if (!viewState) {
|
||||
if (this.renderedVisible_) {
|
||||
this.element_.style.display = 'none';
|
||||
this.renderedVisible_ = false;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
const center = viewState.center;
|
||||
const projection = viewState.projection;
|
||||
const units = this.getUnits();
|
||||
const pointResolutionUnits = units == Units.DEGREES ?
|
||||
ProjUnits.DEGREES :
|
||||
ProjUnits.METERS;
|
||||
let pointResolution =
|
||||
getPointResolution(projection, viewState.resolution, center, pointResolutionUnits);
|
||||
if (projection.getUnits() != ProjUnits.DEGREES && projection.getMetersPerUnit()
|
||||
&& pointResolutionUnits == ProjUnits.METERS) {
|
||||
pointResolution *= projection.getMetersPerUnit();
|
||||
}
|
||||
|
||||
let nominalCount = this.minWidth_ * pointResolution;
|
||||
let suffix = '';
|
||||
if (units == Units.DEGREES) {
|
||||
const metersPerDegree = METERS_PER_UNIT[ProjUnits.DEGREES];
|
||||
if (projection.getUnits() == ProjUnits.DEGREES) {
|
||||
nominalCount *= metersPerDegree;
|
||||
} else {
|
||||
pointResolution /= metersPerDegree;
|
||||
}
|
||||
if (nominalCount < metersPerDegree / 60) {
|
||||
suffix = '\u2033'; // seconds
|
||||
pointResolution *= 3600;
|
||||
} else if (nominalCount < metersPerDegree) {
|
||||
suffix = '\u2032'; // minutes
|
||||
pointResolution *= 60;
|
||||
} else {
|
||||
suffix = '\u00b0'; // degrees
|
||||
}
|
||||
} else if (units == Units.IMPERIAL) {
|
||||
if (nominalCount < 0.9144) {
|
||||
suffix = 'in';
|
||||
pointResolution /= 0.0254;
|
||||
} else if (nominalCount < 1609.344) {
|
||||
suffix = 'ft';
|
||||
pointResolution /= 0.3048;
|
||||
} else {
|
||||
suffix = 'mi';
|
||||
pointResolution /= 1609.344;
|
||||
}
|
||||
} else if (units == Units.NAUTICAL) {
|
||||
pointResolution /= 1852;
|
||||
suffix = 'nm';
|
||||
} else if (units == Units.METRIC) {
|
||||
if (nominalCount < 0.001) {
|
||||
suffix = 'μm';
|
||||
pointResolution *= 1000000;
|
||||
} else if (nominalCount < 1) {
|
||||
suffix = 'mm';
|
||||
pointResolution *= 1000;
|
||||
} else if (nominalCount < 1000) {
|
||||
suffix = 'm';
|
||||
} else {
|
||||
suffix = 'km';
|
||||
pointResolution /= 1000;
|
||||
}
|
||||
} else if (units == Units.US) {
|
||||
if (nominalCount < 0.9144) {
|
||||
suffix = 'in';
|
||||
pointResolution *= 39.37;
|
||||
} else if (nominalCount < 1609.344) {
|
||||
suffix = 'ft';
|
||||
pointResolution /= 0.30480061;
|
||||
} else {
|
||||
suffix = 'mi';
|
||||
pointResolution /= 1609.3472;
|
||||
}
|
||||
} else {
|
||||
assert(false, 33); // Invalid units
|
||||
}
|
||||
|
||||
let i = 3 * Math.floor(
|
||||
Math.log(this.minWidth_ * pointResolution) / Math.log(10));
|
||||
let count, width;
|
||||
while (true) {
|
||||
count = LEADING_DIGITS[((i % 3) + 3) % 3] *
|
||||
Math.pow(10, Math.floor(i / 3));
|
||||
width = Math.round(count / pointResolution);
|
||||
if (isNaN(width)) {
|
||||
this.element_.style.display = 'none';
|
||||
this.renderedVisible_ = false;
|
||||
return;
|
||||
} else if (width >= this.minWidth_) {
|
||||
break;
|
||||
}
|
||||
++i;
|
||||
}
|
||||
|
||||
const html = count + ' ' + suffix;
|
||||
if (this.renderedHTML_ != html) {
|
||||
this.innerElement_.innerHTML = html;
|
||||
this.renderedHTML_ = html;
|
||||
}
|
||||
|
||||
if (this.renderedWidth_ != width) {
|
||||
this.innerElement_.style.width = width + 'px';
|
||||
this.renderedWidth_ = width;
|
||||
}
|
||||
|
||||
if (!this.renderedVisible_) {
|
||||
this.element_.style.display = '';
|
||||
this.renderedVisible_ = true;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
export default ScaleLine;
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
/**
|
||||
* @module ol/control/Zoom
|
||||
*/
|
||||
import {inherits} from '../util.js';
|
||||
import {listen} from '../events.js';
|
||||
import EventType from '../events/EventType.js';
|
||||
import Control from '../control/Control.js';
|
||||
@@ -31,109 +30,108 @@ import {easeOut} from '../easing.js';
|
||||
* This control is one of the default controls of a map. To style this control
|
||||
* use css selectors `.ol-zoom-in` and `.ol-zoom-out`.
|
||||
*
|
||||
* @constructor
|
||||
* @extends {module:ol/control/Control}
|
||||
* @param {module:ol/control/Zoom~Options=} opt_options Zoom options.
|
||||
* @api
|
||||
*/
|
||||
const Zoom = function(opt_options) {
|
||||
|
||||
const options = opt_options ? opt_options : {};
|
||||
|
||||
const className = options.className !== undefined ? options.className : 'ol-zoom';
|
||||
|
||||
const delta = options.delta !== undefined ? options.delta : 1;
|
||||
|
||||
const zoomInLabel = options.zoomInLabel !== undefined ? options.zoomInLabel : '+';
|
||||
const zoomOutLabel = options.zoomOutLabel !== undefined ? options.zoomOutLabel : '\u2212';
|
||||
|
||||
const zoomInTipLabel = options.zoomInTipLabel !== undefined ?
|
||||
options.zoomInTipLabel : 'Zoom in';
|
||||
const zoomOutTipLabel = options.zoomOutTipLabel !== undefined ?
|
||||
options.zoomOutTipLabel : 'Zoom out';
|
||||
|
||||
const inElement = document.createElement('button');
|
||||
inElement.className = className + '-in';
|
||||
inElement.setAttribute('type', 'button');
|
||||
inElement.title = zoomInTipLabel;
|
||||
inElement.appendChild(
|
||||
typeof zoomInLabel === 'string' ? document.createTextNode(zoomInLabel) : zoomInLabel
|
||||
);
|
||||
|
||||
listen(inElement, EventType.CLICK,
|
||||
Zoom.prototype.handleClick_.bind(this, delta));
|
||||
|
||||
const outElement = document.createElement('button');
|
||||
outElement.className = className + '-out';
|
||||
outElement.setAttribute('type', 'button');
|
||||
outElement.title = zoomOutTipLabel;
|
||||
outElement.appendChild(
|
||||
typeof zoomOutLabel === 'string' ? document.createTextNode(zoomOutLabel) : zoomOutLabel
|
||||
);
|
||||
|
||||
listen(outElement, EventType.CLICK,
|
||||
Zoom.prototype.handleClick_.bind(this, -delta));
|
||||
|
||||
const cssClasses = className + ' ' + CLASS_UNSELECTABLE + ' ' + CLASS_CONTROL;
|
||||
const element = document.createElement('div');
|
||||
element.className = cssClasses;
|
||||
element.appendChild(inElement);
|
||||
element.appendChild(outElement);
|
||||
|
||||
Control.call(this, {
|
||||
element: element,
|
||||
target: options.target
|
||||
});
|
||||
class Zoom extends Control {
|
||||
|
||||
/**
|
||||
* @type {number}
|
||||
* @param {module:ol/control/Zoom~Options=} opt_options Zoom options.
|
||||
*/
|
||||
constructor(opt_options) {
|
||||
|
||||
const options = opt_options ? opt_options : {};
|
||||
|
||||
super({
|
||||
element: document.createElement('div'),
|
||||
target: options.target
|
||||
});
|
||||
|
||||
const className = options.className !== undefined ? options.className : 'ol-zoom';
|
||||
|
||||
const delta = options.delta !== undefined ? options.delta : 1;
|
||||
|
||||
const zoomInLabel = options.zoomInLabel !== undefined ? options.zoomInLabel : '+';
|
||||
const zoomOutLabel = options.zoomOutLabel !== undefined ? options.zoomOutLabel : '\u2212';
|
||||
|
||||
const zoomInTipLabel = options.zoomInTipLabel !== undefined ?
|
||||
options.zoomInTipLabel : 'Zoom in';
|
||||
const zoomOutTipLabel = options.zoomOutTipLabel !== undefined ?
|
||||
options.zoomOutTipLabel : 'Zoom out';
|
||||
|
||||
const inElement = document.createElement('button');
|
||||
inElement.className = className + '-in';
|
||||
inElement.setAttribute('type', 'button');
|
||||
inElement.title = zoomInTipLabel;
|
||||
inElement.appendChild(
|
||||
typeof zoomInLabel === 'string' ? document.createTextNode(zoomInLabel) : zoomInLabel
|
||||
);
|
||||
|
||||
listen(inElement, EventType.CLICK, this.handleClick_.bind(this, delta));
|
||||
|
||||
const outElement = document.createElement('button');
|
||||
outElement.className = className + '-out';
|
||||
outElement.setAttribute('type', 'button');
|
||||
outElement.title = zoomOutTipLabel;
|
||||
outElement.appendChild(
|
||||
typeof zoomOutLabel === 'string' ? document.createTextNode(zoomOutLabel) : zoomOutLabel
|
||||
);
|
||||
|
||||
listen(outElement, EventType.CLICK, this.handleClick_.bind(this, -delta));
|
||||
|
||||
const cssClasses = className + ' ' + CLASS_UNSELECTABLE + ' ' + CLASS_CONTROL;
|
||||
const element = this.element;
|
||||
element.className = cssClasses;
|
||||
element.appendChild(inElement);
|
||||
element.appendChild(outElement);
|
||||
|
||||
/**
|
||||
* @type {number}
|
||||
* @private
|
||||
*/
|
||||
this.duration_ = options.duration !== undefined ? options.duration : 250;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {number} delta Zoom delta.
|
||||
* @param {MouseEvent} event The event to handle
|
||||
* @private
|
||||
*/
|
||||
this.duration_ = options.duration !== undefined ? options.duration : 250;
|
||||
|
||||
};
|
||||
|
||||
inherits(Zoom, Control);
|
||||
|
||||
|
||||
/**
|
||||
* @param {number} delta Zoom delta.
|
||||
* @param {MouseEvent} event The event to handle
|
||||
* @private
|
||||
*/
|
||||
Zoom.prototype.handleClick_ = function(delta, event) {
|
||||
event.preventDefault();
|
||||
this.zoomByDelta_(delta);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {number} delta Zoom delta.
|
||||
* @private
|
||||
*/
|
||||
Zoom.prototype.zoomByDelta_ = function(delta) {
|
||||
const map = this.getMap();
|
||||
const view = map.getView();
|
||||
if (!view) {
|
||||
// the map does not have a view, so we can't act
|
||||
// upon it
|
||||
return;
|
||||
handleClick_(delta, event) {
|
||||
event.preventDefault();
|
||||
this.zoomByDelta_(delta);
|
||||
}
|
||||
const currentResolution = view.getResolution();
|
||||
if (currentResolution) {
|
||||
const newResolution = view.constrainResolution(currentResolution, delta);
|
||||
if (this.duration_ > 0) {
|
||||
if (view.getAnimating()) {
|
||||
view.cancelAnimations();
|
||||
|
||||
/**
|
||||
* @param {number} delta Zoom delta.
|
||||
* @private
|
||||
*/
|
||||
zoomByDelta_(delta) {
|
||||
const map = this.getMap();
|
||||
const view = map.getView();
|
||||
if (!view) {
|
||||
// the map does not have a view, so we can't act
|
||||
// upon it
|
||||
return;
|
||||
}
|
||||
const currentResolution = view.getResolution();
|
||||
if (currentResolution) {
|
||||
const newResolution = view.constrainResolution(currentResolution, delta);
|
||||
if (this.duration_ > 0) {
|
||||
if (view.getAnimating()) {
|
||||
view.cancelAnimations();
|
||||
}
|
||||
view.animate({
|
||||
resolution: newResolution,
|
||||
duration: this.duration_,
|
||||
easing: easeOut
|
||||
});
|
||||
} else {
|
||||
view.setResolution(newResolution);
|
||||
}
|
||||
view.animate({
|
||||
resolution: newResolution,
|
||||
duration: this.duration_,
|
||||
easing: easeOut
|
||||
});
|
||||
} else {
|
||||
view.setResolution(newResolution);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
export default Zoom;
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
/**
|
||||
* @module ol/control/ZoomSlider
|
||||
*/
|
||||
import {inherits} from '../util.js';
|
||||
import ViewHint from '../ViewHint.js';
|
||||
import Control from '../control/Control.js';
|
||||
import {CLASS_CONTROL, CLASS_UNSELECTABLE} from '../css.js';
|
||||
@@ -42,167 +41,305 @@ const Direction = {
|
||||
*
|
||||
* map.addControl(new ZoomSlider());
|
||||
*
|
||||
* @constructor
|
||||
* @extends {module:ol/control/Control}
|
||||
* @param {module:ol/control/ZoomSlider~Options=} opt_options Zoom slider options.
|
||||
* @api
|
||||
*/
|
||||
const ZoomSlider = function(opt_options) {
|
||||
|
||||
const options = opt_options ? opt_options : {};
|
||||
class ZoomSlider extends Control {
|
||||
|
||||
/**
|
||||
* Will hold the current resolution of the view.
|
||||
*
|
||||
* @type {number|undefined}
|
||||
* @private
|
||||
* @param {module:ol/control/ZoomSlider~Options=} opt_options Zoom slider options.
|
||||
*/
|
||||
this.currentResolution_ = undefined;
|
||||
constructor(opt_options) {
|
||||
|
||||
/**
|
||||
* The direction of the slider. Will be determined from actual display of the
|
||||
* container and defaults to Direction.VERTICAL.
|
||||
*
|
||||
* @type {Direction}
|
||||
* @private
|
||||
*/
|
||||
this.direction_ = Direction.VERTICAL;
|
||||
const options = opt_options ? opt_options : {};
|
||||
|
||||
/**
|
||||
* @type {boolean}
|
||||
* @private
|
||||
*/
|
||||
this.dragging_;
|
||||
super({
|
||||
element: document.createElement('div'),
|
||||
render: options.render || render
|
||||
});
|
||||
|
||||
/**
|
||||
* @type {number}
|
||||
* @private
|
||||
*/
|
||||
this.heightLimit_ = 0;
|
||||
/**
|
||||
* Will hold the current resolution of the view.
|
||||
*
|
||||
* @type {number|undefined}
|
||||
* @private
|
||||
*/
|
||||
this.currentResolution_ = undefined;
|
||||
|
||||
/**
|
||||
* @type {number}
|
||||
* @private
|
||||
*/
|
||||
this.widthLimit_ = 0;
|
||||
|
||||
/**
|
||||
* @type {number|undefined}
|
||||
* @private
|
||||
*/
|
||||
this.previousX_;
|
||||
|
||||
/**
|
||||
* @type {number|undefined}
|
||||
* @private
|
||||
*/
|
||||
this.previousY_;
|
||||
|
||||
/**
|
||||
* The calculated thumb size (border box plus margins). Set when initSlider_
|
||||
* is called.
|
||||
* @type {module:ol/size~Size}
|
||||
* @private
|
||||
*/
|
||||
this.thumbSize_ = null;
|
||||
|
||||
/**
|
||||
* Whether the slider is initialized.
|
||||
* @type {boolean}
|
||||
* @private
|
||||
*/
|
||||
this.sliderInitialized_ = false;
|
||||
|
||||
/**
|
||||
* @type {number}
|
||||
* @private
|
||||
*/
|
||||
this.duration_ = options.duration !== undefined ? options.duration : 200;
|
||||
|
||||
const className = options.className !== undefined ? options.className : 'ol-zoomslider';
|
||||
const thumbElement = document.createElement('button');
|
||||
thumbElement.setAttribute('type', 'button');
|
||||
thumbElement.className = className + '-thumb ' + CLASS_UNSELECTABLE;
|
||||
const containerElement = document.createElement('div');
|
||||
containerElement.className = className + ' ' + CLASS_UNSELECTABLE + ' ' + CLASS_CONTROL;
|
||||
containerElement.appendChild(thumbElement);
|
||||
/**
|
||||
* @type {module:ol/pointer/PointerEventHandler}
|
||||
* @private
|
||||
*/
|
||||
this.dragger_ = new PointerEventHandler(containerElement);
|
||||
|
||||
listen(this.dragger_, PointerEventType.POINTERDOWN,
|
||||
this.handleDraggerStart_, this);
|
||||
listen(this.dragger_, PointerEventType.POINTERMOVE,
|
||||
this.handleDraggerDrag_, this);
|
||||
listen(this.dragger_, PointerEventType.POINTERUP,
|
||||
this.handleDraggerEnd_, this);
|
||||
|
||||
listen(containerElement, EventType.CLICK, this.handleContainerClick_, this);
|
||||
listen(thumbElement, EventType.CLICK, stopPropagation);
|
||||
|
||||
Control.call(this, {
|
||||
element: containerElement,
|
||||
render: options.render || render
|
||||
});
|
||||
};
|
||||
|
||||
inherits(ZoomSlider, Control);
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
ZoomSlider.prototype.disposeInternal = function() {
|
||||
this.dragger_.dispose();
|
||||
Control.prototype.disposeInternal.call(this);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
ZoomSlider.prototype.setMap = function(map) {
|
||||
Control.prototype.setMap.call(this, map);
|
||||
if (map) {
|
||||
map.render();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Initializes the slider element. This will determine and set this controls
|
||||
* direction_ and also constrain the dragging of the thumb to always be within
|
||||
* the bounds of the container.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
ZoomSlider.prototype.initSlider_ = function() {
|
||||
const container = this.element;
|
||||
const containerSize = {
|
||||
width: container.offsetWidth, height: container.offsetHeight
|
||||
};
|
||||
|
||||
const thumb = container.firstElementChild;
|
||||
const computedStyle = getComputedStyle(thumb);
|
||||
const thumbWidth = thumb.offsetWidth +
|
||||
parseFloat(computedStyle['marginRight']) +
|
||||
parseFloat(computedStyle['marginLeft']);
|
||||
const thumbHeight = thumb.offsetHeight +
|
||||
parseFloat(computedStyle['marginTop']) +
|
||||
parseFloat(computedStyle['marginBottom']);
|
||||
this.thumbSize_ = [thumbWidth, thumbHeight];
|
||||
|
||||
if (containerSize.width > containerSize.height) {
|
||||
this.direction_ = Direction.HORIZONTAL;
|
||||
this.widthLimit_ = containerSize.width - thumbWidth;
|
||||
} else {
|
||||
/**
|
||||
* The direction of the slider. Will be determined from actual display of the
|
||||
* container and defaults to Direction.VERTICAL.
|
||||
*
|
||||
* @type {Direction}
|
||||
* @private
|
||||
*/
|
||||
this.direction_ = Direction.VERTICAL;
|
||||
this.heightLimit_ = containerSize.height - thumbHeight;
|
||||
|
||||
/**
|
||||
* @type {boolean}
|
||||
* @private
|
||||
*/
|
||||
this.dragging_;
|
||||
|
||||
/**
|
||||
* @type {number}
|
||||
* @private
|
||||
*/
|
||||
this.heightLimit_ = 0;
|
||||
|
||||
/**
|
||||
* @type {number}
|
||||
* @private
|
||||
*/
|
||||
this.widthLimit_ = 0;
|
||||
|
||||
/**
|
||||
* @type {number|undefined}
|
||||
* @private
|
||||
*/
|
||||
this.previousX_;
|
||||
|
||||
/**
|
||||
* @type {number|undefined}
|
||||
* @private
|
||||
*/
|
||||
this.previousY_;
|
||||
|
||||
/**
|
||||
* The calculated thumb size (border box plus margins). Set when initSlider_
|
||||
* is called.
|
||||
* @type {module:ol/size~Size}
|
||||
* @private
|
||||
*/
|
||||
this.thumbSize_ = null;
|
||||
|
||||
/**
|
||||
* Whether the slider is initialized.
|
||||
* @type {boolean}
|
||||
* @private
|
||||
*/
|
||||
this.sliderInitialized_ = false;
|
||||
|
||||
/**
|
||||
* @type {number}
|
||||
* @private
|
||||
*/
|
||||
this.duration_ = options.duration !== undefined ? options.duration : 200;
|
||||
|
||||
const className = options.className !== undefined ? options.className : 'ol-zoomslider';
|
||||
const thumbElement = document.createElement('button');
|
||||
thumbElement.setAttribute('type', 'button');
|
||||
thumbElement.className = className + '-thumb ' + CLASS_UNSELECTABLE;
|
||||
const containerElement = this.element;
|
||||
containerElement.className = className + ' ' + CLASS_UNSELECTABLE + ' ' + CLASS_CONTROL;
|
||||
containerElement.appendChild(thumbElement);
|
||||
/**
|
||||
* @type {module:ol/pointer/PointerEventHandler}
|
||||
* @private
|
||||
*/
|
||||
this.dragger_ = new PointerEventHandler(containerElement);
|
||||
|
||||
listen(this.dragger_, PointerEventType.POINTERDOWN,
|
||||
this.handleDraggerStart_, this);
|
||||
listen(this.dragger_, PointerEventType.POINTERMOVE,
|
||||
this.handleDraggerDrag_, this);
|
||||
listen(this.dragger_, PointerEventType.POINTERUP,
|
||||
this.handleDraggerEnd_, this);
|
||||
|
||||
listen(containerElement, EventType.CLICK, this.handleContainerClick_, this);
|
||||
listen(thumbElement, EventType.CLICK, stopPropagation);
|
||||
}
|
||||
this.sliderInitialized_ = true;
|
||||
};
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
disposeInternal() {
|
||||
this.dragger_.dispose();
|
||||
super.disposeInternal();
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
setMap(map) {
|
||||
super.setMap(map);
|
||||
if (map) {
|
||||
map.render();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the slider element. This will determine and set this controls
|
||||
* direction_ and also constrain the dragging of the thumb to always be within
|
||||
* the bounds of the container.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
initSlider_() {
|
||||
const container = this.element;
|
||||
const containerSize = {
|
||||
width: container.offsetWidth, height: container.offsetHeight
|
||||
};
|
||||
|
||||
const thumb = container.firstElementChild;
|
||||
const computedStyle = getComputedStyle(thumb);
|
||||
const thumbWidth = thumb.offsetWidth +
|
||||
parseFloat(computedStyle['marginRight']) +
|
||||
parseFloat(computedStyle['marginLeft']);
|
||||
const thumbHeight = thumb.offsetHeight +
|
||||
parseFloat(computedStyle['marginTop']) +
|
||||
parseFloat(computedStyle['marginBottom']);
|
||||
this.thumbSize_ = [thumbWidth, thumbHeight];
|
||||
|
||||
if (containerSize.width > containerSize.height) {
|
||||
this.direction_ = Direction.HORIZONTAL;
|
||||
this.widthLimit_ = containerSize.width - thumbWidth;
|
||||
} else {
|
||||
this.direction_ = Direction.VERTICAL;
|
||||
this.heightLimit_ = containerSize.height - thumbHeight;
|
||||
}
|
||||
this.sliderInitialized_ = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {MouseEvent} event The browser event to handle.
|
||||
* @private
|
||||
*/
|
||||
handleContainerClick_(event) {
|
||||
const view = this.getMap().getView();
|
||||
|
||||
const relativePosition = this.getRelativePosition_(
|
||||
event.offsetX - this.thumbSize_[0] / 2,
|
||||
event.offsetY - this.thumbSize_[1] / 2);
|
||||
|
||||
const resolution = this.getResolutionForPosition_(relativePosition);
|
||||
|
||||
view.animate({
|
||||
resolution: view.constrainResolution(resolution),
|
||||
duration: this.duration_,
|
||||
easing: easeOut
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle dragger start events.
|
||||
* @param {module:ol/pointer/PointerEvent} event The drag event.
|
||||
* @private
|
||||
*/
|
||||
handleDraggerStart_(event) {
|
||||
if (!this.dragging_ && event.originalEvent.target === this.element.firstElementChild) {
|
||||
this.getMap().getView().setHint(ViewHint.INTERACTING, 1);
|
||||
this.previousX_ = event.clientX;
|
||||
this.previousY_ = event.clientY;
|
||||
this.dragging_ = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle dragger drag events.
|
||||
*
|
||||
* @param {module:ol/pointer/PointerEvent|Event} event The drag event.
|
||||
* @private
|
||||
*/
|
||||
handleDraggerDrag_(event) {
|
||||
if (this.dragging_) {
|
||||
const element = this.element.firstElementChild;
|
||||
const deltaX = event.clientX - this.previousX_ + parseInt(element.style.left, 10);
|
||||
const deltaY = event.clientY - this.previousY_ + parseInt(element.style.top, 10);
|
||||
const relativePosition = this.getRelativePosition_(deltaX, deltaY);
|
||||
this.currentResolution_ = this.getResolutionForPosition_(relativePosition);
|
||||
this.getMap().getView().setResolution(this.currentResolution_);
|
||||
this.setThumbPosition_(this.currentResolution_);
|
||||
this.previousX_ = event.clientX;
|
||||
this.previousY_ = event.clientY;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle dragger end events.
|
||||
* @param {module:ol/pointer/PointerEvent|Event} event The drag event.
|
||||
* @private
|
||||
*/
|
||||
handleDraggerEnd_(event) {
|
||||
if (this.dragging_) {
|
||||
const view = this.getMap().getView();
|
||||
view.setHint(ViewHint.INTERACTING, -1);
|
||||
|
||||
view.animate({
|
||||
resolution: view.constrainResolution(this.currentResolution_),
|
||||
duration: this.duration_,
|
||||
easing: easeOut
|
||||
});
|
||||
|
||||
this.dragging_ = false;
|
||||
this.previousX_ = undefined;
|
||||
this.previousY_ = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Positions the thumb inside its container according to the given resolution.
|
||||
*
|
||||
* @param {number} res The res.
|
||||
* @private
|
||||
*/
|
||||
setThumbPosition_(res) {
|
||||
const position = this.getPositionForResolution_(res);
|
||||
const thumb = this.element.firstElementChild;
|
||||
|
||||
if (this.direction_ == Direction.HORIZONTAL) {
|
||||
thumb.style.left = this.widthLimit_ * position + 'px';
|
||||
} else {
|
||||
thumb.style.top = this.heightLimit_ * position + 'px';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the relative position of the thumb given x and y offsets. The
|
||||
* relative position scales from 0 to 1. The x and y offsets are assumed to be
|
||||
* in pixel units within the dragger limits.
|
||||
*
|
||||
* @param {number} x Pixel position relative to the left of the slider.
|
||||
* @param {number} y Pixel position relative to the top of the slider.
|
||||
* @return {number} The relative position of the thumb.
|
||||
* @private
|
||||
*/
|
||||
getRelativePosition_(x, y) {
|
||||
let amount;
|
||||
if (this.direction_ === Direction.HORIZONTAL) {
|
||||
amount = x / this.widthLimit_;
|
||||
} else {
|
||||
amount = y / this.heightLimit_;
|
||||
}
|
||||
return clamp(amount, 0, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the corresponding resolution of the thumb given its relative
|
||||
* position (where 0 is the minimum and 1 is the maximum).
|
||||
*
|
||||
* @param {number} position The relative position of the thumb.
|
||||
* @return {number} The corresponding resolution.
|
||||
* @private
|
||||
*/
|
||||
getResolutionForPosition_(position) {
|
||||
const fn = this.getMap().getView().getResolutionForValueFunction();
|
||||
return fn(1 - position);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines the relative position of the slider for the given resolution. A
|
||||
* relative position of 0 corresponds to the minimum view resolution. A
|
||||
* relative position of 1 corresponds to the maximum view resolution.
|
||||
*
|
||||
* @param {number} res The resolution.
|
||||
* @return {number} The relative position value (between 0 and 1).
|
||||
* @private
|
||||
*/
|
||||
getPositionForResolution_(res) {
|
||||
const fn = this.getMap().getView().getValueForResolutionFunction();
|
||||
return 1 - fn(res);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
@@ -226,151 +363,4 @@ export function render(mapEvent) {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param {MouseEvent} event The browser event to handle.
|
||||
* @private
|
||||
*/
|
||||
ZoomSlider.prototype.handleContainerClick_ = function(event) {
|
||||
const view = this.getMap().getView();
|
||||
|
||||
const relativePosition = this.getRelativePosition_(
|
||||
event.offsetX - this.thumbSize_[0] / 2,
|
||||
event.offsetY - this.thumbSize_[1] / 2);
|
||||
|
||||
const resolution = this.getResolutionForPosition_(relativePosition);
|
||||
|
||||
view.animate({
|
||||
resolution: view.constrainResolution(resolution),
|
||||
duration: this.duration_,
|
||||
easing: easeOut
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Handle dragger start events.
|
||||
* @param {module:ol/pointer/PointerEvent} event The drag event.
|
||||
* @private
|
||||
*/
|
||||
ZoomSlider.prototype.handleDraggerStart_ = function(event) {
|
||||
if (!this.dragging_ && event.originalEvent.target === this.element.firstElementChild) {
|
||||
this.getMap().getView().setHint(ViewHint.INTERACTING, 1);
|
||||
this.previousX_ = event.clientX;
|
||||
this.previousY_ = event.clientY;
|
||||
this.dragging_ = true;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Handle dragger drag events.
|
||||
*
|
||||
* @param {module:ol/pointer/PointerEvent|Event} event The drag event.
|
||||
* @private
|
||||
*/
|
||||
ZoomSlider.prototype.handleDraggerDrag_ = function(event) {
|
||||
if (this.dragging_) {
|
||||
const element = this.element.firstElementChild;
|
||||
const deltaX = event.clientX - this.previousX_ + parseInt(element.style.left, 10);
|
||||
const deltaY = event.clientY - this.previousY_ + parseInt(element.style.top, 10);
|
||||
const relativePosition = this.getRelativePosition_(deltaX, deltaY);
|
||||
this.currentResolution_ = this.getResolutionForPosition_(relativePosition);
|
||||
this.getMap().getView().setResolution(this.currentResolution_);
|
||||
this.setThumbPosition_(this.currentResolution_);
|
||||
this.previousX_ = event.clientX;
|
||||
this.previousY_ = event.clientY;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Handle dragger end events.
|
||||
* @param {module:ol/pointer/PointerEvent|Event} event The drag event.
|
||||
* @private
|
||||
*/
|
||||
ZoomSlider.prototype.handleDraggerEnd_ = function(event) {
|
||||
if (this.dragging_) {
|
||||
const view = this.getMap().getView();
|
||||
view.setHint(ViewHint.INTERACTING, -1);
|
||||
|
||||
view.animate({
|
||||
resolution: view.constrainResolution(this.currentResolution_),
|
||||
duration: this.duration_,
|
||||
easing: easeOut
|
||||
});
|
||||
|
||||
this.dragging_ = false;
|
||||
this.previousX_ = undefined;
|
||||
this.previousY_ = undefined;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Positions the thumb inside its container according to the given resolution.
|
||||
*
|
||||
* @param {number} res The res.
|
||||
* @private
|
||||
*/
|
||||
ZoomSlider.prototype.setThumbPosition_ = function(res) {
|
||||
const position = this.getPositionForResolution_(res);
|
||||
const thumb = this.element.firstElementChild;
|
||||
|
||||
if (this.direction_ == Direction.HORIZONTAL) {
|
||||
thumb.style.left = this.widthLimit_ * position + 'px';
|
||||
} else {
|
||||
thumb.style.top = this.heightLimit_ * position + 'px';
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Calculates the relative position of the thumb given x and y offsets. The
|
||||
* relative position scales from 0 to 1. The x and y offsets are assumed to be
|
||||
* in pixel units within the dragger limits.
|
||||
*
|
||||
* @param {number} x Pixel position relative to the left of the slider.
|
||||
* @param {number} y Pixel position relative to the top of the slider.
|
||||
* @return {number} The relative position of the thumb.
|
||||
* @private
|
||||
*/
|
||||
ZoomSlider.prototype.getRelativePosition_ = function(x, y) {
|
||||
let amount;
|
||||
if (this.direction_ === Direction.HORIZONTAL) {
|
||||
amount = x / this.widthLimit_;
|
||||
} else {
|
||||
amount = y / this.heightLimit_;
|
||||
}
|
||||
return clamp(amount, 0, 1);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Calculates the corresponding resolution of the thumb given its relative
|
||||
* position (where 0 is the minimum and 1 is the maximum).
|
||||
*
|
||||
* @param {number} position The relative position of the thumb.
|
||||
* @return {number} The corresponding resolution.
|
||||
* @private
|
||||
*/
|
||||
ZoomSlider.prototype.getResolutionForPosition_ = function(position) {
|
||||
const fn = this.getMap().getView().getResolutionForValueFunction();
|
||||
return fn(1 - position);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Determines the relative position of the slider for the given resolution. A
|
||||
* relative position of 0 corresponds to the minimum view resolution. A
|
||||
* relative position of 1 corresponds to the maximum view resolution.
|
||||
*
|
||||
* @param {number} res The resolution.
|
||||
* @return {number} The relative position value (between 0 and 1).
|
||||
* @private
|
||||
*/
|
||||
ZoomSlider.prototype.getPositionForResolution_ = function(res) {
|
||||
const fn = this.getMap().getView().getValueForResolutionFunction();
|
||||
return 1 - fn(res);
|
||||
};
|
||||
|
||||
export default ZoomSlider;
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
/**
|
||||
* @module ol/control/ZoomToExtent
|
||||
*/
|
||||
import {inherits} from '../util.js';
|
||||
import {listen} from '../events.js';
|
||||
import EventType from '../events/EventType.js';
|
||||
import Control from '../control/Control.js';
|
||||
@@ -26,64 +25,64 @@ import {CLASS_CONTROL, CLASS_UNSELECTABLE} from '../css.js';
|
||||
* A button control which, when pressed, changes the map view to a specific
|
||||
* extent. To style this control use the css selector `.ol-zoom-extent`.
|
||||
*
|
||||
* @constructor
|
||||
* @extends {module:ol/control/Control}
|
||||
* @param {module:ol/control/ZoomToExtent~Options=} opt_options Options.
|
||||
* @api
|
||||
*/
|
||||
const ZoomToExtent = function(opt_options) {
|
||||
const options = opt_options ? opt_options : {};
|
||||
class ZoomToExtent extends Control {
|
||||
|
||||
/**
|
||||
* @param {module:ol/control/ZoomToExtent~Options=} opt_options Options.
|
||||
*/
|
||||
constructor(opt_options) {
|
||||
const options = opt_options ? opt_options : {};
|
||||
|
||||
super({
|
||||
element: document.createElement('div'),
|
||||
target: options.target
|
||||
});
|
||||
|
||||
/**
|
||||
* @type {module:ol/extent~Extent}
|
||||
* @protected
|
||||
*/
|
||||
this.extent = options.extent ? options.extent : null;
|
||||
|
||||
const className = options.className !== undefined ? options.className : 'ol-zoom-extent';
|
||||
|
||||
const label = options.label !== undefined ? options.label : 'E';
|
||||
const tipLabel = options.tipLabel !== undefined ? options.tipLabel : 'Fit to extent';
|
||||
const button = document.createElement('button');
|
||||
button.setAttribute('type', 'button');
|
||||
button.title = tipLabel;
|
||||
button.appendChild(
|
||||
typeof label === 'string' ? document.createTextNode(label) : label
|
||||
);
|
||||
|
||||
listen(button, EventType.CLICK, this.handleClick_, this);
|
||||
|
||||
const cssClasses = className + ' ' + CLASS_UNSELECTABLE + ' ' + CLASS_CONTROL;
|
||||
const element = this.element;
|
||||
element.className = cssClasses;
|
||||
element.appendChild(button);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {MouseEvent} event The event to handle
|
||||
* @private
|
||||
*/
|
||||
handleClick_(event) {
|
||||
event.preventDefault();
|
||||
this.handleZoomToExtent();
|
||||
}
|
||||
|
||||
/**
|
||||
* @type {module:ol/extent~Extent}
|
||||
* @protected
|
||||
*/
|
||||
this.extent = options.extent ? options.extent : null;
|
||||
handleZoomToExtent() {
|
||||
const map = this.getMap();
|
||||
const view = map.getView();
|
||||
const extent = !this.extent ? view.getProjection().getExtent() : this.extent;
|
||||
view.fit(extent);
|
||||
}
|
||||
}
|
||||
|
||||
const className = options.className !== undefined ? options.className : 'ol-zoom-extent';
|
||||
|
||||
const label = options.label !== undefined ? options.label : 'E';
|
||||
const tipLabel = options.tipLabel !== undefined ? options.tipLabel : 'Fit to extent';
|
||||
const button = document.createElement('button');
|
||||
button.setAttribute('type', 'button');
|
||||
button.title = tipLabel;
|
||||
button.appendChild(
|
||||
typeof label === 'string' ? document.createTextNode(label) : label
|
||||
);
|
||||
|
||||
listen(button, EventType.CLICK, this.handleClick_, this);
|
||||
|
||||
const cssClasses = className + ' ' + CLASS_UNSELECTABLE + ' ' + CLASS_CONTROL;
|
||||
const element = document.createElement('div');
|
||||
element.className = cssClasses;
|
||||
element.appendChild(button);
|
||||
|
||||
Control.call(this, {
|
||||
element: element,
|
||||
target: options.target
|
||||
});
|
||||
};
|
||||
|
||||
inherits(ZoomToExtent, Control);
|
||||
|
||||
|
||||
/**
|
||||
* @param {MouseEvent} event The event to handle
|
||||
* @private
|
||||
*/
|
||||
ZoomToExtent.prototype.handleClick_ = function(event) {
|
||||
event.preventDefault();
|
||||
this.handleZoomToExtent();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @protected
|
||||
*/
|
||||
ZoomToExtent.prototype.handleZoomToExtent = function() {
|
||||
const map = this.getMap();
|
||||
const view = map.getView();
|
||||
const extent = !this.extent ? view.getProjection().getExtent() : this.extent;
|
||||
view.fit(extent);
|
||||
};
|
||||
export default ZoomToExtent;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
/**
|
||||
* @module ol/events/Event
|
||||
*/
|
||||
|
||||
/**
|
||||
* @classdesc
|
||||
* Stripped down implementation of the W3C DOM Level 2 Event interface.
|
||||
@@ -10,49 +11,53 @@
|
||||
* `stopPropagation` and `preventDefault` methods. It is meant as base class
|
||||
* for higher level events defined in the library, and works with
|
||||
* {@link module:ol/events/EventTarget~EventTarget}.
|
||||
*
|
||||
* @constructor
|
||||
* @param {string} type Type.
|
||||
*/
|
||||
const Event = function(type) {
|
||||
class Event {
|
||||
|
||||
/**
|
||||
* @type {boolean}
|
||||
* @param {string} type Type.
|
||||
*/
|
||||
this.propagationStopped;
|
||||
constructor(type) {
|
||||
|
||||
/**
|
||||
* The event type.
|
||||
* @type {string}
|
||||
* @api
|
||||
*/
|
||||
this.type = type;
|
||||
/**
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.propagationStopped;
|
||||
|
||||
/**
|
||||
* The event target.
|
||||
* @type {Object}
|
||||
* @api
|
||||
*/
|
||||
this.target = null;
|
||||
/**
|
||||
* The event type.
|
||||
* @type {string}
|
||||
* @api
|
||||
*/
|
||||
this.type = type;
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Stop event propagation.
|
||||
* @function
|
||||
* @api
|
||||
*/
|
||||
Event.prototype.preventDefault =
|
||||
/**
|
||||
* The event target.
|
||||
* @type {Object}
|
||||
* @api
|
||||
*/
|
||||
this.target = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop event propagation.
|
||||
* @function
|
||||
* @api
|
||||
*/
|
||||
Event.prototype.stopPropagation = function() {
|
||||
preventDefault() {
|
||||
this.propagationStopped = true;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop event propagation.
|
||||
* @function
|
||||
* @api
|
||||
*/
|
||||
stopPropagation() {
|
||||
this.propagationStopped = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
/**
|
||||
* @module ol/events/EventTarget
|
||||
*/
|
||||
import {inherits} from '../util.js';
|
||||
import Disposable from '../Disposable.js';
|
||||
import {unlistenAll} from '../events.js';
|
||||
import {UNDEFINED} from '../functions.js';
|
||||
@@ -27,141 +26,140 @@ import Event from '../events/Event.js';
|
||||
* `stopPropagation` or `preventDefault` on an event object, it means that no
|
||||
* more listeners after this one will be called. Same as when the listener
|
||||
* returns false.
|
||||
*
|
||||
* @constructor
|
||||
* @extends {module:ol/Disposable}
|
||||
*/
|
||||
const EventTarget = function() {
|
||||
class EventTarget extends Disposable {
|
||||
constructor() {
|
||||
|
||||
Disposable.call(this);
|
||||
super();
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {!Object.<string, number>}
|
||||
*/
|
||||
this.pendingRemovals_ = {};
|
||||
/**
|
||||
* @private
|
||||
* @type {!Object.<string, number>}
|
||||
*/
|
||||
this.pendingRemovals_ = {};
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {!Object.<string, number>}
|
||||
*/
|
||||
this.dispatching_ = {};
|
||||
/**
|
||||
* @private
|
||||
* @type {!Object.<string, number>}
|
||||
*/
|
||||
this.dispatching_ = {};
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {!Object.<string, Array.<module:ol/events~ListenerFunction>>}
|
||||
*/
|
||||
this.listeners_ = {};
|
||||
/**
|
||||
* @private
|
||||
* @type {!Object.<string, Array.<module:ol/events~ListenerFunction>>}
|
||||
*/
|
||||
this.listeners_ = {};
|
||||
|
||||
};
|
||||
|
||||
inherits(EventTarget, Disposable);
|
||||
|
||||
|
||||
/**
|
||||
* @param {string} type Type.
|
||||
* @param {module:ol/events~ListenerFunction} listener Listener.
|
||||
*/
|
||||
EventTarget.prototype.addEventListener = function(type, listener) {
|
||||
let listeners = this.listeners_[type];
|
||||
if (!listeners) {
|
||||
listeners = this.listeners_[type] = [];
|
||||
}
|
||||
if (listeners.indexOf(listener) === -1) {
|
||||
listeners.push(listener);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {{type: string,
|
||||
* target: (EventTarget|module:ol/events/EventTarget|undefined)}|module:ol/events/Event|
|
||||
* string} event Event or event type.
|
||||
* @return {boolean|undefined} `false` if anyone called preventDefault on the
|
||||
* event object or if any of the listeners returned false.
|
||||
*/
|
||||
EventTarget.prototype.dispatchEvent = function(event) {
|
||||
const evt = typeof event === 'string' ? new Event(event) : event;
|
||||
const type = evt.type;
|
||||
evt.target = this;
|
||||
const listeners = this.listeners_[type];
|
||||
let propagate;
|
||||
if (listeners) {
|
||||
if (!(type in this.dispatching_)) {
|
||||
this.dispatching_[type] = 0;
|
||||
this.pendingRemovals_[type] = 0;
|
||||
/**
|
||||
* @param {string} type Type.
|
||||
* @param {module:ol/events~ListenerFunction} listener Listener.
|
||||
*/
|
||||
addEventListener(type, listener) {
|
||||
let listeners = this.listeners_[type];
|
||||
if (!listeners) {
|
||||
listeners = this.listeners_[type] = [];
|
||||
}
|
||||
++this.dispatching_[type];
|
||||
for (let i = 0, ii = listeners.length; i < ii; ++i) {
|
||||
if (listeners[i].call(this, evt) === false || evt.propagationStopped) {
|
||||
propagate = false;
|
||||
break;
|
||||
if (listeners.indexOf(listener) === -1) {
|
||||
listeners.push(listener);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispatches an event and calls all listeners listening for events
|
||||
* of this type. The event parameter can either be a string or an
|
||||
* Object with a `type` property.
|
||||
*
|
||||
* @param {{type: string,
|
||||
* target: (EventTarget|module:ol/events/EventTarget|undefined)}|
|
||||
* module:ol/events/Event|string} event Event object.
|
||||
* @return {boolean|undefined} `false` if anyone called preventDefault on the
|
||||
* event object or if any of the listeners returned false.
|
||||
* @function
|
||||
* @api
|
||||
*/
|
||||
dispatchEvent(event) {
|
||||
const evt = typeof event === 'string' ? new Event(event) : event;
|
||||
const type = evt.type;
|
||||
evt.target = this;
|
||||
const listeners = this.listeners_[type];
|
||||
let propagate;
|
||||
if (listeners) {
|
||||
if (!(type in this.dispatching_)) {
|
||||
this.dispatching_[type] = 0;
|
||||
this.pendingRemovals_[type] = 0;
|
||||
}
|
||||
}
|
||||
--this.dispatching_[type];
|
||||
if (this.dispatching_[type] === 0) {
|
||||
let pendingRemovals = this.pendingRemovals_[type];
|
||||
delete this.pendingRemovals_[type];
|
||||
while (pendingRemovals--) {
|
||||
this.removeEventListener(type, UNDEFINED);
|
||||
++this.dispatching_[type];
|
||||
for (let i = 0, ii = listeners.length; i < ii; ++i) {
|
||||
if (listeners[i].call(this, evt) === false || evt.propagationStopped) {
|
||||
propagate = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
delete this.dispatching_[type];
|
||||
--this.dispatching_[type];
|
||||
if (this.dispatching_[type] === 0) {
|
||||
let pendingRemovals = this.pendingRemovals_[type];
|
||||
delete this.pendingRemovals_[type];
|
||||
while (pendingRemovals--) {
|
||||
this.removeEventListener(type, UNDEFINED);
|
||||
}
|
||||
delete this.dispatching_[type];
|
||||
}
|
||||
return propagate;
|
||||
}
|
||||
return propagate;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
disposeInternal() {
|
||||
unlistenAll(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
EventTarget.prototype.disposeInternal = function() {
|
||||
unlistenAll(this);
|
||||
};
|
||||
/**
|
||||
* Get the listeners for a specified event type. Listeners are returned in the
|
||||
* order that they will be called in.
|
||||
*
|
||||
* @param {string} type Type.
|
||||
* @return {Array.<module:ol/events~ListenerFunction>} Listeners.
|
||||
*/
|
||||
getListeners(type) {
|
||||
return this.listeners_[type];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string=} opt_type Type. If not provided,
|
||||
* `true` will be returned if this EventTarget has any listeners.
|
||||
* @return {boolean} Has listeners.
|
||||
*/
|
||||
hasListener(opt_type) {
|
||||
return opt_type ?
|
||||
opt_type in this.listeners_ :
|
||||
Object.keys(this.listeners_).length > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the listeners for a specified event type. Listeners are returned in the
|
||||
* order that they will be called in.
|
||||
*
|
||||
* @param {string} type Type.
|
||||
* @return {Array.<module:ol/events~ListenerFunction>} Listeners.
|
||||
*/
|
||||
EventTarget.prototype.getListeners = function(type) {
|
||||
return this.listeners_[type];
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {string=} opt_type Type. If not provided,
|
||||
* `true` will be returned if this EventTarget has any listeners.
|
||||
* @return {boolean} Has listeners.
|
||||
*/
|
||||
EventTarget.prototype.hasListener = function(opt_type) {
|
||||
return opt_type ?
|
||||
opt_type in this.listeners_ :
|
||||
Object.keys(this.listeners_).length > 0;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {string} type Type.
|
||||
* @param {module:ol/events~ListenerFunction} listener Listener.
|
||||
*/
|
||||
EventTarget.prototype.removeEventListener = function(type, listener) {
|
||||
const listeners = this.listeners_[type];
|
||||
if (listeners) {
|
||||
const index = listeners.indexOf(listener);
|
||||
if (type in this.pendingRemovals_) {
|
||||
// make listener a no-op, and remove later in #dispatchEvent()
|
||||
listeners[index] = UNDEFINED;
|
||||
++this.pendingRemovals_[type];
|
||||
} else {
|
||||
listeners.splice(index, 1);
|
||||
if (listeners.length === 0) {
|
||||
delete this.listeners_[type];
|
||||
/**
|
||||
* @param {string} type Type.
|
||||
* @param {module:ol/events~ListenerFunction} listener Listener.
|
||||
*/
|
||||
removeEventListener(type, listener) {
|
||||
const listeners = this.listeners_[type];
|
||||
if (listeners) {
|
||||
const index = listeners.indexOf(listener);
|
||||
if (type in this.pendingRemovals_) {
|
||||
// make listener a no-op, and remove later in #dispatchEvent()
|
||||
listeners[index] = UNDEFINED;
|
||||
++this.pendingRemovals_[type];
|
||||
} else {
|
||||
listeners.splice(index, 1);
|
||||
if (listeners.length === 0) {
|
||||
delete this.listeners_[type];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
export default EventTarget;
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
/**
|
||||
* @module ol/format/EsriJSON
|
||||
*/
|
||||
import {inherits} from '../util.js';
|
||||
import Feature from '../Feature.js';
|
||||
import {assert} from '../asserts.js';
|
||||
import {containsExtent} from '../extent.js';
|
||||
@@ -58,27 +57,154 @@ GEOMETRY_WRITERS[GeometryType.MULTI_POLYGON] = writeMultiPolygonGeometry;
|
||||
* @classdesc
|
||||
* Feature format for reading and writing data in the EsriJSON format.
|
||||
*
|
||||
* @constructor
|
||||
* @extends {module:ol/format/JSONFeature}
|
||||
* @param {module:ol/format/EsriJSON~Options=} opt_options Options.
|
||||
* @api
|
||||
*/
|
||||
const EsriJSON = function(opt_options) {
|
||||
|
||||
const options = opt_options ? opt_options : {};
|
||||
|
||||
JSONFeature.call(this);
|
||||
class EsriJSON extends JSONFeature {
|
||||
|
||||
/**
|
||||
* Name of the geometry attribute for features.
|
||||
* @type {string|undefined}
|
||||
* @private
|
||||
* @param {module:ol/format/EsriJSON~Options=} opt_options Options.
|
||||
*/
|
||||
this.geometryName_ = options.geometryName;
|
||||
constructor(opt_options) {
|
||||
|
||||
};
|
||||
const options = opt_options ? opt_options : {};
|
||||
|
||||
inherits(EsriJSON, JSONFeature);
|
||||
super();
|
||||
|
||||
/**
|
||||
* Name of the geometry attribute for features.
|
||||
* @type {string|undefined}
|
||||
* @private
|
||||
*/
|
||||
this.geometryName_ = options.geometryName;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
readFeatureFromObject(object, opt_options) {
|
||||
const esriJSONFeature = /** @type {EsriJSONFeature} */ (object);
|
||||
const geometry = readGeometry(esriJSONFeature.geometry, opt_options);
|
||||
const feature = new Feature();
|
||||
if (this.geometryName_) {
|
||||
feature.setGeometryName(this.geometryName_);
|
||||
}
|
||||
feature.setGeometry(geometry);
|
||||
if (opt_options && opt_options.idField &&
|
||||
esriJSONFeature.attributes[opt_options.idField]) {
|
||||
feature.setId(/** @type {number} */(esriJSONFeature.attributes[opt_options.idField]));
|
||||
}
|
||||
if (esriJSONFeature.attributes) {
|
||||
feature.setProperties(esriJSONFeature.attributes);
|
||||
}
|
||||
return feature;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
readFeaturesFromObject(object, opt_options) {
|
||||
const esriJSONObject = /** @type {EsriJSONObject} */ (object);
|
||||
const options = opt_options ? opt_options : {};
|
||||
if (esriJSONObject.features) {
|
||||
const esriJSONFeatureCollection = /** @type {EsriJSONFeatureCollection} */ (object);
|
||||
/** @type {Array.<module:ol/Feature>} */
|
||||
const features = [];
|
||||
const esriJSONFeatures = esriJSONFeatureCollection.features;
|
||||
options.idField = object.objectIdFieldName;
|
||||
for (let i = 0, ii = esriJSONFeatures.length; i < ii; ++i) {
|
||||
features.push(this.readFeatureFromObject(esriJSONFeatures[i], options));
|
||||
}
|
||||
return features;
|
||||
} else {
|
||||
return [this.readFeatureFromObject(object, options)];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
readGeometryFromObject(object, opt_options) {
|
||||
return readGeometry(/** @type {EsriJSONGeometry} */(object), opt_options);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
readProjectionFromObject(object) {
|
||||
const esriJSONObject = /** @type {EsriJSONObject} */ (object);
|
||||
if (esriJSONObject.spatialReference && esriJSONObject.spatialReference.wkid) {
|
||||
const crs = esriJSONObject.spatialReference.wkid;
|
||||
return getProjection('EPSG:' + crs);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode a geometry as a EsriJSON object.
|
||||
*
|
||||
* @param {module:ol/geom/Geometry} geometry Geometry.
|
||||
* @param {module:ol/format/Feature~WriteOptions=} opt_options Write options.
|
||||
* @return {EsriJSONGeometry} Object.
|
||||
* @override
|
||||
* @api
|
||||
*/
|
||||
writeGeometryObject(geometry, opt_options) {
|
||||
return writeGeometry(geometry, this.adaptOptions(opt_options));
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode a feature as a esriJSON Feature object.
|
||||
*
|
||||
* @param {module:ol/Feature} feature Feature.
|
||||
* @param {module:ol/format/Feature~WriteOptions=} opt_options Write options.
|
||||
* @return {Object} Object.
|
||||
* @override
|
||||
* @api
|
||||
*/
|
||||
writeFeatureObject(feature, opt_options) {
|
||||
opt_options = this.adaptOptions(opt_options);
|
||||
const object = {};
|
||||
const geometry = feature.getGeometry();
|
||||
if (geometry) {
|
||||
object['geometry'] = writeGeometry(geometry, opt_options);
|
||||
if (opt_options && opt_options.featureProjection) {
|
||||
object['geometry']['spatialReference'] = /** @type {EsriJSONCRS} */({
|
||||
wkid: getProjection(opt_options.featureProjection).getCode().split(':').pop()
|
||||
});
|
||||
}
|
||||
}
|
||||
const properties = feature.getProperties();
|
||||
delete properties[feature.getGeometryName()];
|
||||
if (!isEmpty(properties)) {
|
||||
object['attributes'] = properties;
|
||||
} else {
|
||||
object['attributes'] = {};
|
||||
}
|
||||
return object;
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode an array of features as a EsriJSON object.
|
||||
*
|
||||
* @param {Array.<module:ol/Feature>} features Features.
|
||||
* @param {module:ol/format/Feature~WriteOptions=} opt_options Write options.
|
||||
* @return {Object} EsriJSON Object.
|
||||
* @override
|
||||
* @api
|
||||
*/
|
||||
writeFeaturesObject(features, opt_options) {
|
||||
opt_options = this.adaptOptions(opt_options);
|
||||
const objects = [];
|
||||
for (let i = 0, ii = features.length; i < ii; ++i) {
|
||||
objects.push(this.writeFeatureObject(features[i], opt_options));
|
||||
}
|
||||
return /** @type {EsriJSONFeatureCollection} */ ({
|
||||
'features': objects
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
@@ -413,121 +539,6 @@ function writeMultiPolygonGeometry(geometry, opt_options) {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Read a feature from a EsriJSON Feature source. Only works for Feature,
|
||||
* use `readFeatures` to read FeatureCollection source.
|
||||
*
|
||||
* @function
|
||||
* @param {ArrayBuffer|Document|Node|Object|string} source Source.
|
||||
* @param {module:ol/format/Feature~ReadOptions=} opt_options Read options.
|
||||
* @return {module:ol/Feature} Feature.
|
||||
* @api
|
||||
*/
|
||||
EsriJSON.prototype.readFeature;
|
||||
|
||||
|
||||
/**
|
||||
* Read all features from a EsriJSON source. Works with both Feature and
|
||||
* FeatureCollection sources.
|
||||
*
|
||||
* @function
|
||||
* @param {ArrayBuffer|Document|Node|Object|string} source Source.
|
||||
* @param {module:ol/format/Feature~ReadOptions=} opt_options Read options.
|
||||
* @return {Array.<module:ol/Feature>} Features.
|
||||
* @api
|
||||
*/
|
||||
EsriJSON.prototype.readFeatures;
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
EsriJSON.prototype.readFeatureFromObject = function(object, opt_options) {
|
||||
const esriJSONFeature = /** @type {EsriJSONFeature} */ (object);
|
||||
const geometry = readGeometry(esriJSONFeature.geometry, opt_options);
|
||||
const feature = new Feature();
|
||||
if (this.geometryName_) {
|
||||
feature.setGeometryName(this.geometryName_);
|
||||
}
|
||||
feature.setGeometry(geometry);
|
||||
if (opt_options && opt_options.idField &&
|
||||
esriJSONFeature.attributes[opt_options.idField]) {
|
||||
feature.setId(/** @type {number} */(esriJSONFeature.attributes[opt_options.idField]));
|
||||
}
|
||||
if (esriJSONFeature.attributes) {
|
||||
feature.setProperties(esriJSONFeature.attributes);
|
||||
}
|
||||
return feature;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
EsriJSON.prototype.readFeaturesFromObject = function(object, opt_options) {
|
||||
const esriJSONObject = /** @type {EsriJSONObject} */ (object);
|
||||
const options = opt_options ? opt_options : {};
|
||||
if (esriJSONObject.features) {
|
||||
const esriJSONFeatureCollection = /** @type {EsriJSONFeatureCollection} */ (object);
|
||||
/** @type {Array.<module:ol/Feature>} */
|
||||
const features = [];
|
||||
const esriJSONFeatures = esriJSONFeatureCollection.features;
|
||||
options.idField = object.objectIdFieldName;
|
||||
for (let i = 0, ii = esriJSONFeatures.length; i < ii; ++i) {
|
||||
features.push(this.readFeatureFromObject(esriJSONFeatures[i], options));
|
||||
}
|
||||
return features;
|
||||
} else {
|
||||
return [this.readFeatureFromObject(object, options)];
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Read a geometry from a EsriJSON source.
|
||||
*
|
||||
* @function
|
||||
* @param {ArrayBuffer|Document|Node|Object|string} source Source.
|
||||
* @param {module:ol/format/Feature~ReadOptions=} opt_options Read options.
|
||||
* @return {module:ol/geom/Geometry} Geometry.
|
||||
* @api
|
||||
*/
|
||||
EsriJSON.prototype.readGeometry;
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
EsriJSON.prototype.readGeometryFromObject = function(object, opt_options) {
|
||||
return readGeometry(/** @type {EsriJSONGeometry} */(object), opt_options);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Read the projection from a EsriJSON source.
|
||||
*
|
||||
* @function
|
||||
* @param {ArrayBuffer|Document|Node|Object|string} source Source.
|
||||
* @return {module:ol/proj/Projection} Projection.
|
||||
* @api
|
||||
*/
|
||||
EsriJSON.prototype.readProjection;
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
EsriJSON.prototype.readProjectionFromObject = function(object) {
|
||||
const esriJSONObject = /** @type {EsriJSONObject} */ (object);
|
||||
if (esriJSONObject.spatialReference && esriJSONObject.spatialReference.wkid) {
|
||||
const crs = esriJSONObject.spatialReference.wkid;
|
||||
return getProjection('EPSG:' + crs);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {module:ol/geom/Geometry} geometry Geometry.
|
||||
* @param {module:ol/format/Feature~WriteOptions=} opt_options Write options.
|
||||
@@ -540,106 +551,4 @@ function writeGeometry(geometry, opt_options) {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Encode a geometry as a EsriJSON string.
|
||||
*
|
||||
* @function
|
||||
* @param {module:ol/geom/Geometry} geometry Geometry.
|
||||
* @param {module:ol/format/Feature~WriteOptions=} opt_options Write options.
|
||||
* @return {string} EsriJSON.
|
||||
* @api
|
||||
*/
|
||||
EsriJSON.prototype.writeGeometry;
|
||||
|
||||
|
||||
/**
|
||||
* Encode a geometry as a EsriJSON object.
|
||||
*
|
||||
* @param {module:ol/geom/Geometry} geometry Geometry.
|
||||
* @param {module:ol/format/Feature~WriteOptions=} opt_options Write options.
|
||||
* @return {EsriJSONGeometry} Object.
|
||||
* @override
|
||||
* @api
|
||||
*/
|
||||
EsriJSON.prototype.writeGeometryObject = function(geometry, opt_options) {
|
||||
return writeGeometry(geometry, this.adaptOptions(opt_options));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Encode a feature as a EsriJSON Feature string.
|
||||
*
|
||||
* @function
|
||||
* @param {module:ol/Feature} feature Feature.
|
||||
* @param {module:ol/format/Feature~WriteOptions=} opt_options Write options.
|
||||
* @return {string} EsriJSON.
|
||||
* @api
|
||||
*/
|
||||
EsriJSON.prototype.writeFeature;
|
||||
|
||||
|
||||
/**
|
||||
* Encode a feature as a esriJSON Feature object.
|
||||
*
|
||||
* @param {module:ol/Feature} feature Feature.
|
||||
* @param {module:ol/format/Feature~WriteOptions=} opt_options Write options.
|
||||
* @return {Object} Object.
|
||||
* @override
|
||||
* @api
|
||||
*/
|
||||
EsriJSON.prototype.writeFeatureObject = function(feature, opt_options) {
|
||||
opt_options = this.adaptOptions(opt_options);
|
||||
const object = {};
|
||||
const geometry = feature.getGeometry();
|
||||
if (geometry) {
|
||||
object['geometry'] = writeGeometry(geometry, opt_options);
|
||||
if (opt_options && opt_options.featureProjection) {
|
||||
object['geometry']['spatialReference'] = /** @type {EsriJSONCRS} */({
|
||||
wkid: getProjection(opt_options.featureProjection).getCode().split(':').pop()
|
||||
});
|
||||
}
|
||||
}
|
||||
const properties = feature.getProperties();
|
||||
delete properties[feature.getGeometryName()];
|
||||
if (!isEmpty(properties)) {
|
||||
object['attributes'] = properties;
|
||||
} else {
|
||||
object['attributes'] = {};
|
||||
}
|
||||
return object;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Encode an array of features as EsriJSON.
|
||||
*
|
||||
* @function
|
||||
* @param {Array.<module:ol/Feature>} features Features.
|
||||
* @param {module:ol/format/Feature~WriteOptions=} opt_options Write options.
|
||||
* @return {string} EsriJSON.
|
||||
* @api
|
||||
*/
|
||||
EsriJSON.prototype.writeFeatures;
|
||||
|
||||
|
||||
/**
|
||||
* Encode an array of features as a EsriJSON object.
|
||||
*
|
||||
* @param {Array.<module:ol/Feature>} features Features.
|
||||
* @param {module:ol/format/Feature~WriteOptions=} opt_options Write options.
|
||||
* @return {Object} EsriJSON Object.
|
||||
* @override
|
||||
* @api
|
||||
*/
|
||||
EsriJSON.prototype.writeFeaturesObject = function(features, opt_options) {
|
||||
opt_options = this.adaptOptions(opt_options);
|
||||
const objects = [];
|
||||
for (let i = 0, ii = features.length; i < ii; ++i) {
|
||||
objects.push(this.writeFeatureObject(features[i], opt_options));
|
||||
}
|
||||
return /** @type {EsriJSONFeatureCollection} */ ({
|
||||
'features': objects
|
||||
});
|
||||
};
|
||||
|
||||
export default EsriJSON;
|
||||
|
||||
@@ -56,154 +56,144 @@ import {get as getProjection, equivalent as equivalentProjection, transformExten
|
||||
* {@link module:ol/Feature~Feature} objects from a variety of commonly used geospatial
|
||||
* file formats. See the documentation for each format for more details.
|
||||
*
|
||||
* @constructor
|
||||
* @abstract
|
||||
* @api
|
||||
*/
|
||||
const FeatureFormat = function() {
|
||||
class FeatureFormat {
|
||||
constructor() {
|
||||
|
||||
/**
|
||||
* @protected
|
||||
* @type {module:ol/proj/Projection}
|
||||
*/
|
||||
this.dataProjection = null;
|
||||
/**
|
||||
* @protected
|
||||
* @type {module:ol/proj/Projection}
|
||||
*/
|
||||
this.dataProjection = null;
|
||||
|
||||
/**
|
||||
* @protected
|
||||
* @type {module:ol/proj/Projection}
|
||||
*/
|
||||
this.defaultFeatureProjection = null;
|
||||
/**
|
||||
* @protected
|
||||
* @type {module:ol/proj/Projection}
|
||||
*/
|
||||
this.defaultFeatureProjection = null;
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Adds the data projection to the read options.
|
||||
* @param {Document|Node|Object|string} source Source.
|
||||
* @param {module:ol/format/Feature~ReadOptions=} opt_options Options.
|
||||
* @return {module:ol/format/Feature~ReadOptions|undefined} Options.
|
||||
* @protected
|
||||
*/
|
||||
FeatureFormat.prototype.getReadOptions = function(source, opt_options) {
|
||||
let options;
|
||||
if (opt_options) {
|
||||
options = {
|
||||
dataProjection: opt_options.dataProjection ?
|
||||
opt_options.dataProjection : this.readProjection(source),
|
||||
featureProjection: opt_options.featureProjection
|
||||
};
|
||||
}
|
||||
return this.adaptOptions(options);
|
||||
};
|
||||
|
||||
/**
|
||||
* Adds the data projection to the read options.
|
||||
* @param {Document|Node|Object|string} source Source.
|
||||
* @param {module:ol/format/Feature~ReadOptions=} opt_options Options.
|
||||
* @return {module:ol/format/Feature~ReadOptions|undefined} Options.
|
||||
* @protected
|
||||
*/
|
||||
getReadOptions(source, opt_options) {
|
||||
let options;
|
||||
if (opt_options) {
|
||||
options = {
|
||||
dataProjection: opt_options.dataProjection ?
|
||||
opt_options.dataProjection : this.readProjection(source),
|
||||
featureProjection: opt_options.featureProjection
|
||||
};
|
||||
}
|
||||
return this.adaptOptions(options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the `dataProjection` on the options, if no `dataProjection`
|
||||
* is set.
|
||||
* @param {module:ol/format/Feature~WriteOptions|module:ol/format/Feature~ReadOptions|undefined} options
|
||||
* Options.
|
||||
* @protected
|
||||
* @return {module:ol/format/Feature~WriteOptions|module:ol/format/Feature~ReadOptions|undefined}
|
||||
* Updated options.
|
||||
*/
|
||||
FeatureFormat.prototype.adaptOptions = function(options) {
|
||||
return assign({
|
||||
dataProjection: this.dataProjection,
|
||||
featureProjection: this.defaultFeatureProjection
|
||||
}, options);
|
||||
};
|
||||
/**
|
||||
* Sets the `dataProjection` on the options, if no `dataProjection`
|
||||
* is set.
|
||||
* @param {module:ol/format/Feature~WriteOptions|module:ol/format/Feature~ReadOptions|undefined} options
|
||||
* Options.
|
||||
* @protected
|
||||
* @return {module:ol/format/Feature~WriteOptions|module:ol/format/Feature~ReadOptions|undefined}
|
||||
* Updated options.
|
||||
*/
|
||||
adaptOptions(options) {
|
||||
return assign({
|
||||
dataProjection: this.dataProjection,
|
||||
featureProjection: this.defaultFeatureProjection
|
||||
}, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the extent from the source of the last {@link readFeatures} call.
|
||||
* @return {module:ol/extent~Extent} Tile extent.
|
||||
*/
|
||||
getLastExtent() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the extent from the source of the last {@link readFeatures} call.
|
||||
* @return {module:ol/extent~Extent} Tile extent.
|
||||
*/
|
||||
FeatureFormat.prototype.getLastExtent = function() {
|
||||
return null;
|
||||
};
|
||||
/**
|
||||
* @abstract
|
||||
* @return {module:ol/format/FormatType} Format.
|
||||
*/
|
||||
getType() {}
|
||||
|
||||
/**
|
||||
* Read a single feature from a source.
|
||||
*
|
||||
* @abstract
|
||||
* @param {Document|Node|Object|string} source Source.
|
||||
* @param {module:ol/format/Feature~ReadOptions=} opt_options Read options.
|
||||
* @return {module:ol/Feature} Feature.
|
||||
*/
|
||||
readFeature(source, opt_options) {}
|
||||
|
||||
/**
|
||||
* @abstract
|
||||
* @return {module:ol/format/FormatType} Format.
|
||||
*/
|
||||
FeatureFormat.prototype.getType = function() {};
|
||||
/**
|
||||
* Read all features from a source.
|
||||
*
|
||||
* @abstract
|
||||
* @param {Document|Node|ArrayBuffer|Object|string} source Source.
|
||||
* @param {module:ol/format/Feature~ReadOptions=} opt_options Read options.
|
||||
* @return {Array.<module:ol/Feature>} Features.
|
||||
*/
|
||||
readFeatures(source, opt_options) {}
|
||||
|
||||
/**
|
||||
* Read a single geometry from a source.
|
||||
*
|
||||
* @abstract
|
||||
* @param {Document|Node|Object|string} source Source.
|
||||
* @param {module:ol/format/Feature~ReadOptions=} opt_options Read options.
|
||||
* @return {module:ol/geom/Geometry} Geometry.
|
||||
*/
|
||||
readGeometry(source, opt_options) {}
|
||||
|
||||
/**
|
||||
* Read a single feature from a source.
|
||||
*
|
||||
* @abstract
|
||||
* @param {Document|Node|Object|string} source Source.
|
||||
* @param {module:ol/format/Feature~ReadOptions=} opt_options Read options.
|
||||
* @return {module:ol/Feature} Feature.
|
||||
*/
|
||||
FeatureFormat.prototype.readFeature = function(source, opt_options) {};
|
||||
/**
|
||||
* Read the projection from a source.
|
||||
*
|
||||
* @abstract
|
||||
* @param {Document|Node|Object|string} source Source.
|
||||
* @return {module:ol/proj/Projection} Projection.
|
||||
*/
|
||||
readProjection(source) {}
|
||||
|
||||
/**
|
||||
* Encode a feature in this format.
|
||||
*
|
||||
* @abstract
|
||||
* @param {module:ol/Feature} feature Feature.
|
||||
* @param {module:ol/format/Feature~WriteOptions=} opt_options Write options.
|
||||
* @return {string} Result.
|
||||
*/
|
||||
writeFeature(feature, opt_options) {}
|
||||
|
||||
/**
|
||||
* Read all features from a source.
|
||||
*
|
||||
* @abstract
|
||||
* @param {Document|Node|ArrayBuffer|Object|string} source Source.
|
||||
* @param {module:ol/format/Feature~ReadOptions=} opt_options Read options.
|
||||
* @return {Array.<module:ol/Feature>} Features.
|
||||
*/
|
||||
FeatureFormat.prototype.readFeatures = function(source, opt_options) {};
|
||||
/**
|
||||
* Encode an array of features in this format.
|
||||
*
|
||||
* @abstract
|
||||
* @param {Array.<module:ol/Feature>} features Features.
|
||||
* @param {module:ol/format/Feature~WriteOptions=} opt_options Write options.
|
||||
* @return {string} Result.
|
||||
*/
|
||||
writeFeatures(features, opt_options) {}
|
||||
|
||||
|
||||
/**
|
||||
* Read a single geometry from a source.
|
||||
*
|
||||
* @abstract
|
||||
* @param {Document|Node|Object|string} source Source.
|
||||
* @param {module:ol/format/Feature~ReadOptions=} opt_options Read options.
|
||||
* @return {module:ol/geom/Geometry} Geometry.
|
||||
*/
|
||||
FeatureFormat.prototype.readGeometry = function(source, opt_options) {};
|
||||
|
||||
|
||||
/**
|
||||
* Read the projection from a source.
|
||||
*
|
||||
* @abstract
|
||||
* @param {Document|Node|Object|string} source Source.
|
||||
* @return {module:ol/proj/Projection} Projection.
|
||||
*/
|
||||
FeatureFormat.prototype.readProjection = function(source) {};
|
||||
|
||||
|
||||
/**
|
||||
* Encode a feature in this format.
|
||||
*
|
||||
* @abstract
|
||||
* @param {module:ol/Feature} feature Feature.
|
||||
* @param {module:ol/format/Feature~WriteOptions=} opt_options Write options.
|
||||
* @return {string} Result.
|
||||
*/
|
||||
FeatureFormat.prototype.writeFeature = function(feature, opt_options) {};
|
||||
|
||||
|
||||
/**
|
||||
* Encode an array of features in this format.
|
||||
*
|
||||
* @abstract
|
||||
* @param {Array.<module:ol/Feature>} features Features.
|
||||
* @param {module:ol/format/Feature~WriteOptions=} opt_options Write options.
|
||||
* @return {string} Result.
|
||||
*/
|
||||
FeatureFormat.prototype.writeFeatures = function(features, opt_options) {};
|
||||
|
||||
|
||||
/**
|
||||
* Write a single geometry in this format.
|
||||
*
|
||||
* @abstract
|
||||
* @param {module:ol/geom/Geometry} geometry Geometry.
|
||||
* @param {module:ol/format/Feature~WriteOptions=} opt_options Write options.
|
||||
* @return {string} Result.
|
||||
*/
|
||||
FeatureFormat.prototype.writeGeometry = function(geometry, opt_options) {};
|
||||
/**
|
||||
* Write a single geometry in this format.
|
||||
*
|
||||
* @abstract
|
||||
* @param {module:ol/geom/Geometry} geometry Geometry.
|
||||
* @param {module:ol/format/Feature~WriteOptions=} opt_options Write options.
|
||||
* @return {string} Result.
|
||||
*/
|
||||
writeGeometry(geometry, opt_options) {}
|
||||
}
|
||||
|
||||
export default FeatureFormat;
|
||||
|
||||
|
||||
@@ -9,10 +9,8 @@ import GML3 from '../format/GML3.js';
|
||||
* version 3.1.1.
|
||||
* Currently only supports GML 3.1.1 Simple Features profile.
|
||||
*
|
||||
* @constructor
|
||||
* @param {module:ol/format/GMLBase~Options=} opt_options
|
||||
* Optional configuration object.
|
||||
* @extends {module:ol/format/GMLBase}
|
||||
* @api
|
||||
*/
|
||||
const GML = GML3;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -4,7 +4,6 @@
|
||||
// FIXME Envelopes should not be treated as geometries! readEnvelope_ is part
|
||||
// of GEOMETRY_PARSERS_ and methods using GEOMETRY_PARSERS_ do not expect
|
||||
// envelopes/extents, only geometries!
|
||||
import {inherits} from '../util.js';
|
||||
import {extend} from '../array.js';
|
||||
import Feature from '../Feature.js';
|
||||
import {transformWithOptions} from '../format/Feature.js';
|
||||
@@ -29,6 +28,20 @@ import {getAllTextContent, getAttributeNS, makeArrayPusher, makeReplacer, parseN
|
||||
export const GMLNS = 'http://www.opengis.net/gml';
|
||||
|
||||
|
||||
/**
|
||||
* A regular expression that matches if a string only contains whitespace
|
||||
* characters. It will e.g. match `''`, `' '`, `'\n'` etc. The non-breaking
|
||||
* space (0xa0) is explicitly included as IE doesn't include it in its
|
||||
* definition of `\s`.
|
||||
*
|
||||
* Information from `goog.string.isEmptyOrWhitespace`: https://github.com/google/closure-library/blob/e877b1e/closure/goog/string/string.js#L156-L160
|
||||
*
|
||||
* @const
|
||||
* @type {RegExp}
|
||||
*/
|
||||
const ONLY_WHITESPACE_RE = /^[\s\xa0]*$/;
|
||||
|
||||
|
||||
/**
|
||||
* @typedef {Object} Options
|
||||
* @property {Object.<string, string>|string} [featureNS] Feature
|
||||
@@ -69,390 +82,392 @@ export const GMLNS = 'http://www.opengis.net/gml';
|
||||
* This class cannot be instantiated, it contains only base content that
|
||||
* is shared with versioned format classes GML2 and GML3.
|
||||
*
|
||||
* @constructor
|
||||
* @abstract
|
||||
* @param {module:ol/format/GMLBase~Options=} opt_options
|
||||
* Optional configuration object.
|
||||
* @extends {module:ol/format/XMLFeature}
|
||||
*/
|
||||
const GMLBase = function(opt_options) {
|
||||
const options = /** @type {module:ol/format/GMLBase~Options} */ (opt_options ? opt_options : {});
|
||||
class GMLBase extends XMLFeature {
|
||||
|
||||
/**
|
||||
* @protected
|
||||
* @type {Array.<string>|string|undefined}
|
||||
* @param {module:ol/format/GMLBase~Options=} opt_options Optional configuration object.
|
||||
*/
|
||||
this.featureType = options.featureType;
|
||||
constructor(opt_options) {
|
||||
super();
|
||||
|
||||
const options = /** @type {module:ol/format/GMLBase~Options} */ (opt_options ? opt_options : {});
|
||||
|
||||
/**
|
||||
* @protected
|
||||
* @type {Array.<string>|string|undefined}
|
||||
*/
|
||||
this.featureType = options.featureType;
|
||||
|
||||
/**
|
||||
* @protected
|
||||
* @type {Object.<string, string>|string|undefined}
|
||||
*/
|
||||
this.featureNS = options.featureNS;
|
||||
|
||||
/**
|
||||
* @protected
|
||||
* @type {string}
|
||||
*/
|
||||
this.srsName = options.srsName;
|
||||
|
||||
/**
|
||||
* @protected
|
||||
* @type {string}
|
||||
*/
|
||||
this.schemaLocation = '';
|
||||
|
||||
/**
|
||||
* @type {Object.<string, Object.<string, Object>>}
|
||||
*/
|
||||
this.FEATURE_COLLECTION_PARSERS = {};
|
||||
this.FEATURE_COLLECTION_PARSERS[GMLNS] = {
|
||||
'featureMember': makeReplacer(this.readFeaturesInternal),
|
||||
'featureMembers': makeReplacer(this.readFeaturesInternal)
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @protected
|
||||
* @type {Object.<string, string>|string|undefined}
|
||||
* @param {Node} node Node.
|
||||
* @param {Array.<*>} objectStack Object stack.
|
||||
* @return {Array.<module:ol/Feature> | undefined} Features.
|
||||
*/
|
||||
this.featureNS = options.featureNS;
|
||||
|
||||
/**
|
||||
* @protected
|
||||
* @type {string}
|
||||
*/
|
||||
this.srsName = options.srsName;
|
||||
|
||||
/**
|
||||
* @protected
|
||||
* @type {string}
|
||||
*/
|
||||
this.schemaLocation = '';
|
||||
|
||||
/**
|
||||
* @type {Object.<string, Object.<string, Object>>}
|
||||
*/
|
||||
this.FEATURE_COLLECTION_PARSERS = {};
|
||||
this.FEATURE_COLLECTION_PARSERS[GMLNS] = {
|
||||
'featureMember': makeReplacer(GMLBase.prototype.readFeaturesInternal),
|
||||
'featureMembers': makeReplacer(GMLBase.prototype.readFeaturesInternal)
|
||||
};
|
||||
|
||||
XMLFeature.call(this);
|
||||
};
|
||||
|
||||
inherits(GMLBase, XMLFeature);
|
||||
|
||||
|
||||
/**
|
||||
* A regular expression that matches if a string only contains whitespace
|
||||
* characters. It will e.g. match `''`, `' '`, `'\n'` etc. The non-breaking
|
||||
* space (0xa0) is explicitly included as IE doesn't include it in its
|
||||
* definition of `\s`.
|
||||
*
|
||||
* Information from `goog.string.isEmptyOrWhitespace`: https://github.com/google/closure-library/blob/e877b1e/closure/goog/string/string.js#L156-L160
|
||||
*
|
||||
* @const
|
||||
* @type {RegExp}
|
||||
*/
|
||||
const ONLY_WHITESPACE_RE = /^[\s\xa0]*$/;
|
||||
|
||||
|
||||
/**
|
||||
* @param {Node} node Node.
|
||||
* @param {Array.<*>} objectStack Object stack.
|
||||
* @return {Array.<module:ol/Feature> | undefined} Features.
|
||||
*/
|
||||
GMLBase.prototype.readFeaturesInternal = function(node, objectStack) {
|
||||
const localName = node.localName;
|
||||
let features = null;
|
||||
if (localName == 'FeatureCollection') {
|
||||
if (node.namespaceURI === 'http://www.opengis.net/wfs') {
|
||||
features = pushParseAndPop([],
|
||||
this.FEATURE_COLLECTION_PARSERS, node,
|
||||
objectStack, this);
|
||||
} else {
|
||||
features = pushParseAndPop(null,
|
||||
this.FEATURE_COLLECTION_PARSERS, node,
|
||||
objectStack, this);
|
||||
}
|
||||
} else if (localName == 'featureMembers' || localName == 'featureMember') {
|
||||
const context = objectStack[0];
|
||||
let featureType = context['featureType'];
|
||||
let featureNS = context['featureNS'];
|
||||
const prefix = 'p';
|
||||
const defaultPrefix = 'p0';
|
||||
if (!featureType && node.childNodes) {
|
||||
featureType = [], featureNS = {};
|
||||
for (let i = 0, ii = node.childNodes.length; i < ii; ++i) {
|
||||
const child = node.childNodes[i];
|
||||
if (child.nodeType === 1) {
|
||||
const ft = child.nodeName.split(':').pop();
|
||||
if (featureType.indexOf(ft) === -1) {
|
||||
let key = '';
|
||||
let count = 0;
|
||||
const uri = child.namespaceURI;
|
||||
for (const candidate in featureNS) {
|
||||
if (featureNS[candidate] === uri) {
|
||||
key = candidate;
|
||||
break;
|
||||
readFeaturesInternal(node, objectStack) {
|
||||
const localName = node.localName;
|
||||
let features = null;
|
||||
if (localName == 'FeatureCollection') {
|
||||
if (node.namespaceURI === 'http://www.opengis.net/wfs') {
|
||||
features = pushParseAndPop([],
|
||||
this.FEATURE_COLLECTION_PARSERS, node,
|
||||
objectStack, this);
|
||||
} else {
|
||||
features = pushParseAndPop(null,
|
||||
this.FEATURE_COLLECTION_PARSERS, node,
|
||||
objectStack, this);
|
||||
}
|
||||
} else if (localName == 'featureMembers' || localName == 'featureMember') {
|
||||
const context = objectStack[0];
|
||||
let featureType = context['featureType'];
|
||||
let featureNS = context['featureNS'];
|
||||
const prefix = 'p';
|
||||
const defaultPrefix = 'p0';
|
||||
if (!featureType && node.childNodes) {
|
||||
featureType = [], featureNS = {};
|
||||
for (let i = 0, ii = node.childNodes.length; i < ii; ++i) {
|
||||
const child = node.childNodes[i];
|
||||
if (child.nodeType === 1) {
|
||||
const ft = child.nodeName.split(':').pop();
|
||||
if (featureType.indexOf(ft) === -1) {
|
||||
let key = '';
|
||||
let count = 0;
|
||||
const uri = child.namespaceURI;
|
||||
for (const candidate in featureNS) {
|
||||
if (featureNS[candidate] === uri) {
|
||||
key = candidate;
|
||||
break;
|
||||
}
|
||||
++count;
|
||||
}
|
||||
++count;
|
||||
if (!key) {
|
||||
key = prefix + count;
|
||||
featureNS[key] = uri;
|
||||
}
|
||||
featureType.push(key + ':' + ft);
|
||||
}
|
||||
if (!key) {
|
||||
key = prefix + count;
|
||||
featureNS[key] = uri;
|
||||
}
|
||||
featureType.push(key + ':' + ft);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (localName != 'featureMember') {
|
||||
// recheck featureType for each featureMember
|
||||
context['featureType'] = featureType;
|
||||
context['featureNS'] = featureNS;
|
||||
}
|
||||
}
|
||||
if (typeof featureNS === 'string') {
|
||||
const ns = featureNS;
|
||||
featureNS = {};
|
||||
featureNS[defaultPrefix] = ns;
|
||||
}
|
||||
const parsersNS = {};
|
||||
const featureTypes = Array.isArray(featureType) ? featureType : [featureType];
|
||||
for (const p in featureNS) {
|
||||
const parsers = {};
|
||||
for (let i = 0, ii = featureTypes.length; i < ii; ++i) {
|
||||
const featurePrefix = featureTypes[i].indexOf(':') === -1 ?
|
||||
defaultPrefix : featureTypes[i].split(':')[0];
|
||||
if (featurePrefix === p) {
|
||||
parsers[featureTypes[i].split(':').pop()] =
|
||||
(localName == 'featureMembers') ?
|
||||
makeArrayPusher(this.readFeatureElement, this) :
|
||||
makeReplacer(this.readFeatureElement, this);
|
||||
if (localName != 'featureMember') {
|
||||
// recheck featureType for each featureMember
|
||||
context['featureType'] = featureType;
|
||||
context['featureNS'] = featureNS;
|
||||
}
|
||||
}
|
||||
parsersNS[featureNS[p]] = parsers;
|
||||
}
|
||||
if (localName == 'featureMember') {
|
||||
features = pushParseAndPop(undefined, parsersNS, node, objectStack);
|
||||
} else {
|
||||
features = pushParseAndPop([], parsersNS, node, objectStack);
|
||||
}
|
||||
}
|
||||
if (features === null) {
|
||||
features = [];
|
||||
}
|
||||
return features;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {Node} node Node.
|
||||
* @param {Array.<*>} objectStack Object stack.
|
||||
* @return {module:ol/geom/Geometry|undefined} Geometry.
|
||||
*/
|
||||
GMLBase.prototype.readGeometryElement = function(node, objectStack) {
|
||||
const context = /** @type {Object} */ (objectStack[0]);
|
||||
context['srsName'] = node.firstElementChild.getAttribute('srsName');
|
||||
context['srsDimension'] = node.firstElementChild.getAttribute('srsDimension');
|
||||
/** @type {module:ol/geom/Geometry} */
|
||||
const geometry = pushParseAndPop(null, this.GEOMETRY_PARSERS_, node, objectStack, this);
|
||||
if (geometry) {
|
||||
return (
|
||||
/** @type {module:ol/geom/Geometry} */ (transformWithOptions(geometry, false, context))
|
||||
);
|
||||
} else {
|
||||
return undefined;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {Node} node Node.
|
||||
* @param {Array.<*>} objectStack Object stack.
|
||||
* @return {module:ol/Feature} Feature.
|
||||
*/
|
||||
GMLBase.prototype.readFeatureElement = function(node, objectStack) {
|
||||
let n;
|
||||
const fid = node.getAttribute('fid') || getAttributeNS(node, GMLNS, 'id');
|
||||
const values = {};
|
||||
let geometryName;
|
||||
for (n = node.firstElementChild; n; n = n.nextElementSibling) {
|
||||
const localName = n.localName;
|
||||
// Assume attribute elements have one child node and that the child
|
||||
// is a text or CDATA node (to be treated as text).
|
||||
// Otherwise assume it is a geometry node.
|
||||
if (n.childNodes.length === 0 ||
|
||||
(n.childNodes.length === 1 &&
|
||||
(n.firstChild.nodeType === 3 || n.firstChild.nodeType === 4))) {
|
||||
let value = getAllTextContent(n, false);
|
||||
if (ONLY_WHITESPACE_RE.test(value)) {
|
||||
value = undefined;
|
||||
if (typeof featureNS === 'string') {
|
||||
const ns = featureNS;
|
||||
featureNS = {};
|
||||
featureNS[defaultPrefix] = ns;
|
||||
}
|
||||
values[localName] = value;
|
||||
} else {
|
||||
// boundedBy is an extent and must not be considered as a geometry
|
||||
if (localName !== 'boundedBy') {
|
||||
geometryName = localName;
|
||||
const parsersNS = {};
|
||||
const featureTypes = Array.isArray(featureType) ? featureType : [featureType];
|
||||
for (const p in featureNS) {
|
||||
const parsers = {};
|
||||
for (let i = 0, ii = featureTypes.length; i < ii; ++i) {
|
||||
const featurePrefix = featureTypes[i].indexOf(':') === -1 ?
|
||||
defaultPrefix : featureTypes[i].split(':')[0];
|
||||
if (featurePrefix === p) {
|
||||
parsers[featureTypes[i].split(':').pop()] =
|
||||
(localName == 'featureMembers') ?
|
||||
makeArrayPusher(this.readFeatureElement, this) :
|
||||
makeReplacer(this.readFeatureElement, this);
|
||||
}
|
||||
}
|
||||
parsersNS[featureNS[p]] = parsers;
|
||||
}
|
||||
values[localName] = this.readGeometryElement(n, objectStack);
|
||||
if (localName == 'featureMember') {
|
||||
features = pushParseAndPop(undefined, parsersNS, node, objectStack);
|
||||
} else {
|
||||
features = pushParseAndPop([], parsersNS, node, objectStack);
|
||||
}
|
||||
}
|
||||
if (features === null) {
|
||||
features = [];
|
||||
}
|
||||
return features;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Node} node Node.
|
||||
* @param {Array.<*>} objectStack Object stack.
|
||||
* @return {module:ol/geom/Geometry|undefined} Geometry.
|
||||
*/
|
||||
readGeometryElement(node, objectStack) {
|
||||
const context = /** @type {Object} */ (objectStack[0]);
|
||||
context['srsName'] = node.firstElementChild.getAttribute('srsName');
|
||||
context['srsDimension'] = node.firstElementChild.getAttribute('srsDimension');
|
||||
/** @type {module:ol/geom/Geometry} */
|
||||
const geometry = pushParseAndPop(null, this.GEOMETRY_PARSERS_, node, objectStack, this);
|
||||
if (geometry) {
|
||||
return (
|
||||
/** @type {module:ol/geom/Geometry} */ (transformWithOptions(geometry, false, context))
|
||||
);
|
||||
} else {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
const feature = new Feature(values);
|
||||
if (geometryName) {
|
||||
feature.setGeometryName(geometryName);
|
||||
}
|
||||
if (fid) {
|
||||
feature.setId(fid);
|
||||
}
|
||||
return feature;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {Node} node Node.
|
||||
* @param {Array.<*>} objectStack Object stack.
|
||||
* @return {module:ol/geom/Point|undefined} Point.
|
||||
*/
|
||||
GMLBase.prototype.readPoint = function(node, objectStack) {
|
||||
const flatCoordinates = this.readFlatCoordinatesFromNode_(node, objectStack);
|
||||
if (flatCoordinates) {
|
||||
return new Point(flatCoordinates, GeometryLayout.XYZ);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {Node} node Node.
|
||||
* @param {Array.<*>} objectStack Object stack.
|
||||
* @return {module:ol/geom/MultiPoint|undefined} MultiPoint.
|
||||
*/
|
||||
GMLBase.prototype.readMultiPoint = function(node, objectStack) {
|
||||
/** @type {Array.<Array.<number>>} */
|
||||
const coordinates = pushParseAndPop([],
|
||||
this.MULTIPOINT_PARSERS_, node, objectStack, this);
|
||||
if (coordinates) {
|
||||
return new MultiPoint(coordinates);
|
||||
} else {
|
||||
return undefined;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {Node} node Node.
|
||||
* @param {Array.<*>} objectStack Object stack.
|
||||
* @return {module:ol/geom/MultiLineString|undefined} MultiLineString.
|
||||
*/
|
||||
GMLBase.prototype.readMultiLineString = function(node, objectStack) {
|
||||
/** @type {Array.<module:ol/geom/LineString>} */
|
||||
const lineStrings = pushParseAndPop([],
|
||||
this.MULTILINESTRING_PARSERS_, node, objectStack, this);
|
||||
if (lineStrings) {
|
||||
return new MultiLineString(lineStrings);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {Node} node Node.
|
||||
* @param {Array.<*>} objectStack Object stack.
|
||||
* @return {module:ol/geom/MultiPolygon|undefined} MultiPolygon.
|
||||
*/
|
||||
GMLBase.prototype.readMultiPolygon = function(node, objectStack) {
|
||||
/** @type {Array.<module:ol/geom/Polygon>} */
|
||||
const polygons = pushParseAndPop([], this.MULTIPOLYGON_PARSERS_, node, objectStack, this);
|
||||
if (polygons) {
|
||||
return new MultiPolygon(polygons);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {Node} node Node.
|
||||
* @param {Array.<*>} objectStack Object stack.
|
||||
* @private
|
||||
*/
|
||||
GMLBase.prototype.pointMemberParser_ = function(node, objectStack) {
|
||||
parseNode(this.POINTMEMBER_PARSERS_, node, objectStack, this);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {Node} node Node.
|
||||
* @param {Array.<*>} objectStack Object stack.
|
||||
* @private
|
||||
*/
|
||||
GMLBase.prototype.lineStringMemberParser_ = function(node, objectStack) {
|
||||
parseNode(this.LINESTRINGMEMBER_PARSERS_, node, objectStack, this);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {Node} node Node.
|
||||
* @param {Array.<*>} objectStack Object stack.
|
||||
* @private
|
||||
*/
|
||||
GMLBase.prototype.polygonMemberParser_ = function(node, objectStack) {
|
||||
parseNode(this.POLYGONMEMBER_PARSERS_, node, objectStack, this);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {Node} node Node.
|
||||
* @param {Array.<*>} objectStack Object stack.
|
||||
* @return {module:ol/geom/LineString|undefined} LineString.
|
||||
*/
|
||||
GMLBase.prototype.readLineString = function(node, objectStack) {
|
||||
const flatCoordinates = this.readFlatCoordinatesFromNode_(node, objectStack);
|
||||
if (flatCoordinates) {
|
||||
const lineString = new LineString(flatCoordinates, GeometryLayout.XYZ);
|
||||
return lineString;
|
||||
} else {
|
||||
return undefined;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {Node} node Node.
|
||||
* @param {Array.<*>} objectStack Object stack.
|
||||
* @private
|
||||
* @return {Array.<number>|undefined} LinearRing flat coordinates.
|
||||
*/
|
||||
GMLBase.prototype.readFlatLinearRing_ = function(node, objectStack) {
|
||||
const ring = pushParseAndPop(null,
|
||||
this.GEOMETRY_FLAT_COORDINATES_PARSERS_, node,
|
||||
objectStack, this);
|
||||
if (ring) {
|
||||
return ring;
|
||||
} else {
|
||||
return undefined;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {Node} node Node.
|
||||
* @param {Array.<*>} objectStack Object stack.
|
||||
* @return {module:ol/geom/LinearRing|undefined} LinearRing.
|
||||
*/
|
||||
GMLBase.prototype.readLinearRing = function(node, objectStack) {
|
||||
const flatCoordinates = this.readFlatCoordinatesFromNode_(node, objectStack);
|
||||
if (flatCoordinates) {
|
||||
return new LinearRing(flatCoordinates, GeometryLayout.XYZ);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {Node} node Node.
|
||||
* @param {Array.<*>} objectStack Object stack.
|
||||
* @return {module:ol/geom/Polygon|undefined} Polygon.
|
||||
*/
|
||||
GMLBase.prototype.readPolygon = function(node, objectStack) {
|
||||
/** @type {Array.<Array.<number>>} */
|
||||
const flatLinearRings = pushParseAndPop([null],
|
||||
this.FLAT_LINEAR_RINGS_PARSERS_, node, objectStack, this);
|
||||
if (flatLinearRings && flatLinearRings[0]) {
|
||||
const flatCoordinates = flatLinearRings[0];
|
||||
const ends = [flatCoordinates.length];
|
||||
let i, ii;
|
||||
for (i = 1, ii = flatLinearRings.length; i < ii; ++i) {
|
||||
extend(flatCoordinates, flatLinearRings[i]);
|
||||
ends.push(flatCoordinates.length);
|
||||
/**
|
||||
* @param {Node} node Node.
|
||||
* @param {Array.<*>} objectStack Object stack.
|
||||
* @return {module:ol/Feature} Feature.
|
||||
*/
|
||||
readFeatureElement(node, objectStack) {
|
||||
let n;
|
||||
const fid = node.getAttribute('fid') || getAttributeNS(node, GMLNS, 'id');
|
||||
const values = {};
|
||||
let geometryName;
|
||||
for (n = node.firstElementChild; n; n = n.nextElementSibling) {
|
||||
const localName = n.localName;
|
||||
// Assume attribute elements have one child node and that the child
|
||||
// is a text or CDATA node (to be treated as text).
|
||||
// Otherwise assume it is a geometry node.
|
||||
if (n.childNodes.length === 0 ||
|
||||
(n.childNodes.length === 1 &&
|
||||
(n.firstChild.nodeType === 3 || n.firstChild.nodeType === 4))) {
|
||||
let value = getAllTextContent(n, false);
|
||||
if (ONLY_WHITESPACE_RE.test(value)) {
|
||||
value = undefined;
|
||||
}
|
||||
values[localName] = value;
|
||||
} else {
|
||||
// boundedBy is an extent and must not be considered as a geometry
|
||||
if (localName !== 'boundedBy') {
|
||||
geometryName = localName;
|
||||
}
|
||||
values[localName] = this.readGeometryElement(n, objectStack);
|
||||
}
|
||||
}
|
||||
return new Polygon(flatCoordinates, GeometryLayout.XYZ, ends);
|
||||
} else {
|
||||
return undefined;
|
||||
const feature = new Feature(values);
|
||||
if (geometryName) {
|
||||
feature.setGeometryName(geometryName);
|
||||
}
|
||||
if (fid) {
|
||||
feature.setId(fid);
|
||||
}
|
||||
return feature;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {Node} node Node.
|
||||
* @param {Array.<*>} objectStack Object stack.
|
||||
* @return {module:ol/geom/Point|undefined} Point.
|
||||
*/
|
||||
readPoint(node, objectStack) {
|
||||
const flatCoordinates = this.readFlatCoordinatesFromNode_(node, objectStack);
|
||||
if (flatCoordinates) {
|
||||
return new Point(flatCoordinates, GeometryLayout.XYZ);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Node} node Node.
|
||||
* @param {Array.<*>} objectStack Object stack.
|
||||
* @private
|
||||
* @return {Array.<number>} Flat coordinates.
|
||||
*/
|
||||
GMLBase.prototype.readFlatCoordinatesFromNode_ = function(node, objectStack) {
|
||||
return pushParseAndPop(null, this.GEOMETRY_FLAT_COORDINATES_PARSERS_, node, objectStack, this);
|
||||
};
|
||||
/**
|
||||
* @param {Node} node Node.
|
||||
* @param {Array.<*>} objectStack Object stack.
|
||||
* @return {module:ol/geom/MultiPoint|undefined} MultiPoint.
|
||||
*/
|
||||
readMultiPoint(node, objectStack) {
|
||||
/** @type {Array.<Array.<number>>} */
|
||||
const coordinates = pushParseAndPop([],
|
||||
this.MULTIPOINT_PARSERS_, node, objectStack, this);
|
||||
if (coordinates) {
|
||||
return new MultiPoint(coordinates);
|
||||
} else {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Node} node Node.
|
||||
* @param {Array.<*>} objectStack Object stack.
|
||||
* @return {module:ol/geom/MultiLineString|undefined} MultiLineString.
|
||||
*/
|
||||
readMultiLineString(node, objectStack) {
|
||||
/** @type {Array.<module:ol/geom/LineString>} */
|
||||
const lineStrings = pushParseAndPop([],
|
||||
this.MULTILINESTRING_PARSERS_, node, objectStack, this);
|
||||
if (lineStrings) {
|
||||
return new MultiLineString(lineStrings);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Node} node Node.
|
||||
* @param {Array.<*>} objectStack Object stack.
|
||||
* @return {module:ol/geom/MultiPolygon|undefined} MultiPolygon.
|
||||
*/
|
||||
readMultiPolygon(node, objectStack) {
|
||||
/** @type {Array.<module:ol/geom/Polygon>} */
|
||||
const polygons = pushParseAndPop([], this.MULTIPOLYGON_PARSERS_, node, objectStack, this);
|
||||
if (polygons) {
|
||||
return new MultiPolygon(polygons);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Node} node Node.
|
||||
* @param {Array.<*>} objectStack Object stack.
|
||||
* @private
|
||||
*/
|
||||
pointMemberParser_(node, objectStack) {
|
||||
parseNode(this.POINTMEMBER_PARSERS_, node, objectStack, this);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Node} node Node.
|
||||
* @param {Array.<*>} objectStack Object stack.
|
||||
* @private
|
||||
*/
|
||||
lineStringMemberParser_(node, objectStack) {
|
||||
parseNode(this.LINESTRINGMEMBER_PARSERS_, node, objectStack, this);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Node} node Node.
|
||||
* @param {Array.<*>} objectStack Object stack.
|
||||
* @private
|
||||
*/
|
||||
polygonMemberParser_(node, objectStack) {
|
||||
parseNode(this.POLYGONMEMBER_PARSERS_, node, objectStack, this);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Node} node Node.
|
||||
* @param {Array.<*>} objectStack Object stack.
|
||||
* @return {module:ol/geom/LineString|undefined} LineString.
|
||||
*/
|
||||
readLineString(node, objectStack) {
|
||||
const flatCoordinates = this.readFlatCoordinatesFromNode_(node, objectStack);
|
||||
if (flatCoordinates) {
|
||||
const lineString = new LineString(flatCoordinates, GeometryLayout.XYZ);
|
||||
return lineString;
|
||||
} else {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Node} node Node.
|
||||
* @param {Array.<*>} objectStack Object stack.
|
||||
* @private
|
||||
* @return {Array.<number>|undefined} LinearRing flat coordinates.
|
||||
*/
|
||||
readFlatLinearRing_(node, objectStack) {
|
||||
const ring = pushParseAndPop(null,
|
||||
this.GEOMETRY_FLAT_COORDINATES_PARSERS_, node,
|
||||
objectStack, this);
|
||||
if (ring) {
|
||||
return ring;
|
||||
} else {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Node} node Node.
|
||||
* @param {Array.<*>} objectStack Object stack.
|
||||
* @return {module:ol/geom/LinearRing|undefined} LinearRing.
|
||||
*/
|
||||
readLinearRing(node, objectStack) {
|
||||
const flatCoordinates = this.readFlatCoordinatesFromNode_(node, objectStack);
|
||||
if (flatCoordinates) {
|
||||
return new LinearRing(flatCoordinates, GeometryLayout.XYZ);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Node} node Node.
|
||||
* @param {Array.<*>} objectStack Object stack.
|
||||
* @return {module:ol/geom/Polygon|undefined} Polygon.
|
||||
*/
|
||||
readPolygon(node, objectStack) {
|
||||
/** @type {Array.<Array.<number>>} */
|
||||
const flatLinearRings = pushParseAndPop([null],
|
||||
this.FLAT_LINEAR_RINGS_PARSERS_, node, objectStack, this);
|
||||
if (flatLinearRings && flatLinearRings[0]) {
|
||||
const flatCoordinates = flatLinearRings[0];
|
||||
const ends = [flatCoordinates.length];
|
||||
let i, ii;
|
||||
for (i = 1, ii = flatLinearRings.length; i < ii; ++i) {
|
||||
extend(flatCoordinates, flatLinearRings[i]);
|
||||
ends.push(flatCoordinates.length);
|
||||
}
|
||||
return new Polygon(flatCoordinates, GeometryLayout.XYZ, ends);
|
||||
} else {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Node} node Node.
|
||||
* @param {Array.<*>} objectStack Object stack.
|
||||
* @private
|
||||
* @return {Array.<number>} Flat coordinates.
|
||||
*/
|
||||
readFlatCoordinatesFromNode_(node, objectStack) {
|
||||
return pushParseAndPop(null, this.GEOMETRY_FLAT_COORDINATES_PARSERS_, node, objectStack, this);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
readGeometryFromNode(node, opt_options) {
|
||||
const geometry = this.readGeometryElement(node,
|
||||
[this.getReadOptions(node, opt_options ? opt_options : {})]);
|
||||
return geometry ? geometry : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
readFeaturesFromNode(node, opt_options) {
|
||||
const options = {
|
||||
featureType: this.featureType,
|
||||
featureNS: this.featureNS
|
||||
};
|
||||
if (opt_options) {
|
||||
assign(options, this.getReadOptions(node, opt_options));
|
||||
}
|
||||
const features = this.readFeaturesInternal(node, [options]);
|
||||
return features || [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
readProjectionFromNode(node) {
|
||||
return getProjection(this.srsName ? this.srsName : node.firstElementChild.getAttribute('srsName'));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @const
|
||||
@@ -540,49 +555,4 @@ GMLBase.prototype.RING_PARSERS = {
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
GMLBase.prototype.readGeometryFromNode = function(node, opt_options) {
|
||||
const geometry = this.readGeometryElement(node,
|
||||
[this.getReadOptions(node, opt_options ? opt_options : {})]);
|
||||
return geometry ? geometry : null;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Read all features from a GML FeatureCollection.
|
||||
*
|
||||
* @function
|
||||
* @param {Document|Node|Object|string} source Source.
|
||||
* @param {module:ol/format/Feature~ReadOptions=} opt_options Options.
|
||||
* @return {Array.<module:ol/Feature>} Features.
|
||||
* @api
|
||||
*/
|
||||
GMLBase.prototype.readFeatures;
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
GMLBase.prototype.readFeaturesFromNode = function(node, opt_options) {
|
||||
const options = {
|
||||
featureType: this.featureType,
|
||||
featureNS: this.featureNS
|
||||
};
|
||||
if (opt_options) {
|
||||
assign(options, this.getReadOptions(node, opt_options));
|
||||
}
|
||||
const features = this.readFeaturesInternal(node, [options]);
|
||||
return features || [];
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
GMLBase.prototype.readProjectionFromNode = function(node) {
|
||||
return getProjection(this.srsName ? this.srsName : node.firstElementChild.getAttribute('srsName'));
|
||||
};
|
||||
export default GMLBase;
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
/**
|
||||
* @module ol/format/GPX
|
||||
*/
|
||||
import {inherits} from '../util.js';
|
||||
import Feature from '../Feature.js';
|
||||
import {includes} from '../array.js';
|
||||
import {transformWithOptions} from '../format/Feature.js';
|
||||
@@ -18,52 +17,6 @@ import {createElementNS, makeArrayPusher, makeArraySerializer, makeChildAppender
|
||||
XML_SCHEMA_INSTANCE_URI} from '../xml.js';
|
||||
|
||||
|
||||
/**
|
||||
* @typedef {Object} Options
|
||||
* @property {function(module:ol/Feature, Node)} [readExtensions] Callback function
|
||||
* to process `extensions` nodes. To prevent memory leaks, this callback function must
|
||||
* not store any references to the node. Note that the `extensions`
|
||||
* node is not allowed in GPX 1.0. Moreover, only `extensions`
|
||||
* nodes from `wpt`, `rte` and `trk` can be processed, as those are
|
||||
* directly mapped to a feature.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} LayoutOptions
|
||||
* @property {boolean} [hasZ]
|
||||
* @property {boolean} [hasM]
|
||||
*/
|
||||
|
||||
/**
|
||||
* @classdesc
|
||||
* Feature format for reading and writing data in the GPX format.
|
||||
*
|
||||
* @constructor
|
||||
* @extends {module:ol/format/XMLFeature}
|
||||
* @param {module:ol/format/GPX~Options=} opt_options Options.
|
||||
* @api
|
||||
*/
|
||||
const GPX = function(opt_options) {
|
||||
|
||||
const options = opt_options ? opt_options : {};
|
||||
|
||||
XMLFeature.call(this);
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
this.dataProjection = getProjection('EPSG:4326');
|
||||
|
||||
/**
|
||||
* @type {function(module:ol/Feature, Node)|undefined}
|
||||
* @private
|
||||
*/
|
||||
this.readExtensions_ = options.readExtensions;
|
||||
};
|
||||
|
||||
inherits(GPX, XMLFeature);
|
||||
|
||||
|
||||
/**
|
||||
* @const
|
||||
* @type {Array.<null|string>}
|
||||
@@ -117,6 +70,159 @@ const LINK_PARSERS = makeStructureNS(
|
||||
});
|
||||
|
||||
|
||||
/**
|
||||
* @const
|
||||
* @type {Object.<string, Object.<string, module:ol/xml~Serializer>>}
|
||||
*/
|
||||
const GPX_SERIALIZERS = makeStructureNS(
|
||||
NAMESPACE_URIS, {
|
||||
'rte': makeChildAppender(writeRte),
|
||||
'trk': makeChildAppender(writeTrk),
|
||||
'wpt': makeChildAppender(writeWpt)
|
||||
});
|
||||
|
||||
|
||||
/**
|
||||
* @typedef {Object} Options
|
||||
* @property {function(module:ol/Feature, Node)} [readExtensions] Callback function
|
||||
* to process `extensions` nodes. To prevent memory leaks, this callback function must
|
||||
* not store any references to the node. Note that the `extensions`
|
||||
* node is not allowed in GPX 1.0. Moreover, only `extensions`
|
||||
* nodes from `wpt`, `rte` and `trk` can be processed, as those are
|
||||
* directly mapped to a feature.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} LayoutOptions
|
||||
* @property {boolean} [hasZ]
|
||||
* @property {boolean} [hasM]
|
||||
*/
|
||||
|
||||
/**
|
||||
* @classdesc
|
||||
* Feature format for reading and writing data in the GPX format.
|
||||
*
|
||||
* Note that {@link module:ol/format/GPX~GPX#readFeature} only reads the first
|
||||
* feature of the source.
|
||||
*
|
||||
* When reading, routes (`<rte>`) are converted into LineString geometries, and
|
||||
* tracks (`<trk>`) into MultiLineString. Any properties on route and track
|
||||
* waypoints are ignored.
|
||||
*
|
||||
* When writing, LineString geometries are output as routes (`<rte>`), and
|
||||
* MultiLineString as tracks (`<trk>`).
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
class GPX extends XMLFeature {
|
||||
|
||||
/**
|
||||
* @param {module:ol/format/GPX~Options=} opt_options Options.
|
||||
*/
|
||||
constructor(opt_options) {
|
||||
super();
|
||||
|
||||
const options = opt_options ? opt_options : {};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
this.dataProjection = getProjection('EPSG:4326');
|
||||
|
||||
/**
|
||||
* @type {function(module:ol/Feature, Node)|undefined}
|
||||
* @private
|
||||
*/
|
||||
this.readExtensions_ = options.readExtensions;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Array.<module:ol/Feature>} features List of features.
|
||||
* @private
|
||||
*/
|
||||
handleReadExtensions_(features) {
|
||||
if (!features) {
|
||||
features = [];
|
||||
}
|
||||
for (let i = 0, ii = features.length; i < ii; ++i) {
|
||||
const feature = features[i];
|
||||
if (this.readExtensions_) {
|
||||
const extensionsNode = feature.get('extensionsNode_') || null;
|
||||
this.readExtensions_(feature, extensionsNode);
|
||||
}
|
||||
feature.set('extensionsNode_', undefined);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
readFeatureFromNode(node, opt_options) {
|
||||
if (!includes(NAMESPACE_URIS, node.namespaceURI)) {
|
||||
return null;
|
||||
}
|
||||
const featureReader = FEATURE_READER[node.localName];
|
||||
if (!featureReader) {
|
||||
return null;
|
||||
}
|
||||
const feature = featureReader(node, [this.getReadOptions(node, opt_options)]);
|
||||
if (!feature) {
|
||||
return null;
|
||||
}
|
||||
this.handleReadExtensions_([feature]);
|
||||
return feature;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
readFeaturesFromNode(node, opt_options) {
|
||||
if (!includes(NAMESPACE_URIS, node.namespaceURI)) {
|
||||
return [];
|
||||
}
|
||||
if (node.localName == 'gpx') {
|
||||
/** @type {Array.<module:ol/Feature>} */
|
||||
const features = pushParseAndPop([], GPX_PARSERS,
|
||||
node, [this.getReadOptions(node, opt_options)]);
|
||||
if (features) {
|
||||
this.handleReadExtensions_(features);
|
||||
return features;
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode an array of features in the GPX format as an XML node.
|
||||
* LineString geometries are output as routes (`<rte>`), and MultiLineString
|
||||
* as tracks (`<trk>`).
|
||||
*
|
||||
* @param {Array.<module:ol/Feature>} features Features.
|
||||
* @param {module:ol/format/Feature~WriteOptions=} opt_options Options.
|
||||
* @return {Node} Node.
|
||||
* @override
|
||||
* @api
|
||||
*/
|
||||
writeFeaturesNode(features, opt_options) {
|
||||
opt_options = this.adaptOptions(opt_options);
|
||||
//FIXME Serialize metadata
|
||||
const gpx = createElementNS('http://www.topografix.com/GPX/1/1', 'gpx');
|
||||
const xmlnsUri = 'http://www.w3.org/2000/xmlns/';
|
||||
gpx.setAttributeNS(xmlnsUri, 'xmlns:xsi', XML_SCHEMA_INSTANCE_URI);
|
||||
gpx.setAttributeNS(XML_SCHEMA_INSTANCE_URI, 'xsi:schemaLocation', SCHEMA_LOCATION);
|
||||
gpx.setAttribute('version', '1.1');
|
||||
gpx.setAttribute('creator', 'OpenLayers');
|
||||
|
||||
pushSerializeAndPop(/** @type {module:ol/xml~NodeStackItem} */
|
||||
({node: gpx}), GPX_SERIALIZERS, GPX_NODE_FACTORY, features, [opt_options]);
|
||||
return gpx;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @const
|
||||
* @type {Object.<string, Object.<string, module:ol/xml~Parser>>}
|
||||
@@ -380,18 +486,6 @@ function GPX_NODE_FACTORY(value, objectStack, opt_nodeName) {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @const
|
||||
* @type {Object.<string, Object.<string, module:ol/xml~Serializer>>}
|
||||
*/
|
||||
const GPX_SERIALIZERS = makeStructureNS(
|
||||
NAMESPACE_URIS, {
|
||||
'rte': makeChildAppender(writeRte),
|
||||
'trk': makeChildAppender(writeTrk),
|
||||
'wpt': makeChildAppender(writeWpt)
|
||||
});
|
||||
|
||||
|
||||
/**
|
||||
* @param {Array.<number>} flatCoordinates Flat coordinates.
|
||||
* @param {module:ol/format/GPX~LayoutOptions} layoutOptions Layout options.
|
||||
@@ -614,106 +708,6 @@ function readWpt(node, objectStack) {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param {Array.<module:ol/Feature>} features List of features.
|
||||
* @private
|
||||
*/
|
||||
GPX.prototype.handleReadExtensions_ = function(features) {
|
||||
if (!features) {
|
||||
features = [];
|
||||
}
|
||||
for (let i = 0, ii = features.length; i < ii; ++i) {
|
||||
const feature = features[i];
|
||||
if (this.readExtensions_) {
|
||||
const extensionsNode = feature.get('extensionsNode_') || null;
|
||||
this.readExtensions_(feature, extensionsNode);
|
||||
}
|
||||
feature.set('extensionsNode_', undefined);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Read the first feature from a GPX source.
|
||||
* Routes (`<rte>`) are converted into LineString geometries, and tracks (`<trk>`)
|
||||
* into MultiLineString. Any properties on route and track waypoints are ignored.
|
||||
*
|
||||
* @function
|
||||
* @param {Document|Node|Object|string} source Source.
|
||||
* @param {module:ol/format/Feature~ReadOptions=} opt_options Read options.
|
||||
* @return {module:ol/Feature} Feature.
|
||||
* @api
|
||||
*/
|
||||
GPX.prototype.readFeature;
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
GPX.prototype.readFeatureFromNode = function(node, opt_options) {
|
||||
if (!includes(NAMESPACE_URIS, node.namespaceURI)) {
|
||||
return null;
|
||||
}
|
||||
const featureReader = FEATURE_READER[node.localName];
|
||||
if (!featureReader) {
|
||||
return null;
|
||||
}
|
||||
const feature = featureReader(node, [this.getReadOptions(node, opt_options)]);
|
||||
if (!feature) {
|
||||
return null;
|
||||
}
|
||||
this.handleReadExtensions_([feature]);
|
||||
return feature;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Read all features from a GPX source.
|
||||
* Routes (`<rte>`) are converted into LineString geometries, and tracks (`<trk>`)
|
||||
* into MultiLineString. Any properties on route and track waypoints are ignored.
|
||||
*
|
||||
* @function
|
||||
* @param {Document|Node|Object|string} source Source.
|
||||
* @param {module:ol/format/Feature~ReadOptions=} opt_options Read options.
|
||||
* @return {Array.<module:ol/Feature>} Features.
|
||||
* @api
|
||||
*/
|
||||
GPX.prototype.readFeatures;
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
GPX.prototype.readFeaturesFromNode = function(node, opt_options) {
|
||||
if (!includes(NAMESPACE_URIS, node.namespaceURI)) {
|
||||
return [];
|
||||
}
|
||||
if (node.localName == 'gpx') {
|
||||
/** @type {Array.<module:ol/Feature>} */
|
||||
const features = pushParseAndPop([], GPX_PARSERS,
|
||||
node, [this.getReadOptions(node, opt_options)]);
|
||||
if (features) {
|
||||
this.handleReadExtensions_(features);
|
||||
return features;
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
return [];
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Read the projection from a GPX source.
|
||||
*
|
||||
* @function
|
||||
* @param {Document|Node|Object|string} source Source.
|
||||
* @return {module:ol/proj/Projection} Projection.
|
||||
* @api
|
||||
*/
|
||||
GPX.prototype.readProjection;
|
||||
|
||||
|
||||
/**
|
||||
* @param {Node} node Node.
|
||||
* @param {string} value Value for the link's `href` attribute.
|
||||
@@ -860,43 +854,4 @@ function writeWpt(node, feature, objectStack) {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Encode an array of features in the GPX format.
|
||||
* LineString geometries are output as routes (`<rte>`), and MultiLineString
|
||||
* as tracks (`<trk>`).
|
||||
*
|
||||
* @function
|
||||
* @param {Array.<module:ol/Feature>} features Features.
|
||||
* @param {module:ol/format/Feature~WriteOptions=} opt_options Write options.
|
||||
* @return {string} Result.
|
||||
* @api
|
||||
*/
|
||||
GPX.prototype.writeFeatures;
|
||||
|
||||
|
||||
/**
|
||||
* Encode an array of features in the GPX format as an XML node.
|
||||
* LineString geometries are output as routes (`<rte>`), and MultiLineString
|
||||
* as tracks (`<trk>`).
|
||||
*
|
||||
* @param {Array.<module:ol/Feature>} features Features.
|
||||
* @param {module:ol/format/Feature~WriteOptions=} opt_options Options.
|
||||
* @return {Node} Node.
|
||||
* @override
|
||||
* @api
|
||||
*/
|
||||
GPX.prototype.writeFeaturesNode = function(features, opt_options) {
|
||||
opt_options = this.adaptOptions(opt_options);
|
||||
//FIXME Serialize metadata
|
||||
const gpx = createElementNS('http://www.topografix.com/GPX/1/1', 'gpx');
|
||||
const xmlnsUri = 'http://www.w3.org/2000/xmlns/';
|
||||
gpx.setAttributeNS(xmlnsUri, 'xmlns:xsi', XML_SCHEMA_INSTANCE_URI);
|
||||
gpx.setAttributeNS(XML_SCHEMA_INSTANCE_URI, 'xsi:schemaLocation', SCHEMA_LOCATION);
|
||||
gpx.setAttribute('version', '1.1');
|
||||
gpx.setAttribute('creator', 'OpenLayers');
|
||||
|
||||
pushSerializeAndPop(/** @type {module:ol/xml~NodeStackItem} */
|
||||
({node: gpx}), GPX_SERIALIZERS, GPX_NODE_FACTORY, features, [opt_options]);
|
||||
return gpx;
|
||||
};
|
||||
export default GPX;
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
// TODO: serialize dataProjection as crs member when writing
|
||||
// see https://github.com/openlayers/openlayers/issues/2078
|
||||
|
||||
import {inherits} from '../util.js';
|
||||
import {assert} from '../asserts.js';
|
||||
import Feature from '../Feature.js';
|
||||
import {transformWithOptions} from '../format/Feature.js';
|
||||
@@ -37,45 +36,197 @@ import {get as getProjection} from '../proj.js';
|
||||
* @classdesc
|
||||
* Feature format for reading and writing data in the GeoJSON format.
|
||||
*
|
||||
* @constructor
|
||||
* @extends {module:ol/format/JSONFeature}
|
||||
* @param {module:ol/format/GeoJSON~Options=} opt_options Options.
|
||||
* @api
|
||||
* @api
|
||||
*/
|
||||
const GeoJSON = function(opt_options) {
|
||||
class GeoJSON extends JSONFeature {
|
||||
|
||||
const options = opt_options ? opt_options : {};
|
||||
/**
|
||||
* @param {module:ol/format/GeoJSON~Options=} opt_options Options.
|
||||
*/
|
||||
constructor(opt_options) {
|
||||
|
||||
JSONFeature.call(this);
|
||||
const options = opt_options ? opt_options : {};
|
||||
|
||||
super();
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
this.dataProjection = getProjection(
|
||||
options.dataProjection ?
|
||||
options.dataProjection : 'EPSG:4326');
|
||||
|
||||
if (options.featureProjection) {
|
||||
this.defaultFeatureProjection = getProjection(options.featureProjection);
|
||||
}
|
||||
|
||||
/**
|
||||
* Name of the geometry attribute for features.
|
||||
* @type {string|undefined}
|
||||
* @private
|
||||
*/
|
||||
this.geometryName_ = options.geometryName;
|
||||
|
||||
/**
|
||||
* Look for the geometry name in the feature GeoJSON
|
||||
* @type {boolean|undefined}
|
||||
* @private
|
||||
*/
|
||||
this.extractGeometryName_ = options.extractGeometryName;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
this.dataProjection = getProjection(
|
||||
options.dataProjection ?
|
||||
options.dataProjection : 'EPSG:4326');
|
||||
readFeatureFromObject(object, opt_options) {
|
||||
/**
|
||||
* @type {GeoJSONFeature}
|
||||
*/
|
||||
let geoJSONFeature = null;
|
||||
if (object.type === 'Feature') {
|
||||
geoJSONFeature = /** @type {GeoJSONFeature} */ (object);
|
||||
} else {
|
||||
geoJSONFeature = /** @type {GeoJSONFeature} */ ({
|
||||
type: 'Feature',
|
||||
geometry: /** @type {GeoJSONGeometry|GeoJSONGeometryCollection} */ (object)
|
||||
});
|
||||
}
|
||||
|
||||
if (options.featureProjection) {
|
||||
this.defaultFeatureProjection = getProjection(options.featureProjection);
|
||||
const geometry = readGeometry(geoJSONFeature.geometry, opt_options);
|
||||
const feature = new Feature();
|
||||
if (this.geometryName_) {
|
||||
feature.setGeometryName(this.geometryName_);
|
||||
} else if (this.extractGeometryName_ && geoJSONFeature.geometry_name !== undefined) {
|
||||
feature.setGeometryName(geoJSONFeature.geometry_name);
|
||||
}
|
||||
feature.setGeometry(geometry);
|
||||
if (geoJSONFeature.id !== undefined) {
|
||||
feature.setId(geoJSONFeature.id);
|
||||
}
|
||||
if (geoJSONFeature.properties) {
|
||||
feature.setProperties(geoJSONFeature.properties);
|
||||
}
|
||||
return feature;
|
||||
}
|
||||
|
||||
/**
|
||||
* Name of the geometry attribute for features.
|
||||
* @type {string|undefined}
|
||||
* @private
|
||||
* @inheritDoc
|
||||
*/
|
||||
this.geometryName_ = options.geometryName;
|
||||
readFeaturesFromObject(object, opt_options) {
|
||||
const geoJSONObject = /** @type {GeoJSONObject} */ (object);
|
||||
/** @type {Array.<module:ol/Feature>} */
|
||||
let features = null;
|
||||
if (geoJSONObject.type === 'FeatureCollection') {
|
||||
const geoJSONFeatureCollection = /** @type {GeoJSONFeatureCollection} */ (object);
|
||||
features = [];
|
||||
const geoJSONFeatures = geoJSONFeatureCollection.features;
|
||||
for (let i = 0, ii = geoJSONFeatures.length; i < ii; ++i) {
|
||||
features.push(this.readFeatureFromObject(geoJSONFeatures[i], opt_options));
|
||||
}
|
||||
} else {
|
||||
features = [this.readFeatureFromObject(object, opt_options)];
|
||||
}
|
||||
return features;
|
||||
}
|
||||
|
||||
/**
|
||||
* Look for the geometry name in the feature GeoJSON
|
||||
* @type {boolean|undefined}
|
||||
* @private
|
||||
* @inheritDoc
|
||||
*/
|
||||
this.extractGeometryName_ = options.extractGeometryName;
|
||||
readGeometryFromObject(object, opt_options) {
|
||||
return readGeometry(/** @type {GeoJSONGeometry} */ (object), opt_options);
|
||||
}
|
||||
|
||||
};
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
readProjectionFromObject(object) {
|
||||
const geoJSONObject = /** @type {GeoJSONObject} */ (object);
|
||||
const crs = geoJSONObject.crs;
|
||||
let projection;
|
||||
if (crs) {
|
||||
if (crs.type == 'name') {
|
||||
projection = getProjection(crs.properties.name);
|
||||
} else {
|
||||
assert(false, 36); // Unknown SRS type
|
||||
}
|
||||
} else {
|
||||
projection = this.dataProjection;
|
||||
}
|
||||
return (
|
||||
/** @type {module:ol/proj/Projection} */ (projection)
|
||||
);
|
||||
}
|
||||
|
||||
inherits(GeoJSON, JSONFeature);
|
||||
/**
|
||||
* Encode a feature as a GeoJSON Feature object.
|
||||
*
|
||||
* @param {module:ol/Feature} feature Feature.
|
||||
* @param {module:ol/format/Feature~WriteOptions=} opt_options Write options.
|
||||
* @return {GeoJSONFeature} Object.
|
||||
* @override
|
||||
* @api
|
||||
*/
|
||||
writeFeatureObject(feature, opt_options) {
|
||||
opt_options = this.adaptOptions(opt_options);
|
||||
|
||||
const object = /** @type {GeoJSONFeature} */ ({
|
||||
'type': 'Feature'
|
||||
});
|
||||
const id = feature.getId();
|
||||
if (id !== undefined) {
|
||||
object.id = id;
|
||||
}
|
||||
const geometry = feature.getGeometry();
|
||||
if (geometry) {
|
||||
object.geometry = writeGeometry(geometry, opt_options);
|
||||
} else {
|
||||
object.geometry = null;
|
||||
}
|
||||
const properties = feature.getProperties();
|
||||
delete properties[feature.getGeometryName()];
|
||||
if (!isEmpty(properties)) {
|
||||
object.properties = properties;
|
||||
} else {
|
||||
object.properties = null;
|
||||
}
|
||||
return object;
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode an array of features as a GeoJSON object.
|
||||
*
|
||||
* @param {Array.<module:ol/Feature>} features Features.
|
||||
* @param {module:ol/format/Feature~WriteOptions=} opt_options Write options.
|
||||
* @return {GeoJSONFeatureCollection} GeoJSON Object.
|
||||
* @override
|
||||
* @api
|
||||
*/
|
||||
writeFeaturesObject(features, opt_options) {
|
||||
opt_options = this.adaptOptions(opt_options);
|
||||
const objects = [];
|
||||
for (let i = 0, ii = features.length; i < ii; ++i) {
|
||||
objects.push(this.writeFeatureObject(features[i], opt_options));
|
||||
}
|
||||
return /** @type {GeoJSONFeatureCollection} */ ({
|
||||
type: 'FeatureCollection',
|
||||
features: objects
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode a geometry as a GeoJSON object.
|
||||
*
|
||||
* @param {module:ol/geom/Geometry} geometry Geometry.
|
||||
* @param {module:ol/format/Feature~WriteOptions=} opt_options Write options.
|
||||
* @return {GeoJSONGeometry|GeoJSONGeometryCollection} Object.
|
||||
* @override
|
||||
* @api
|
||||
*/
|
||||
writeGeometryObject(geometry, opt_options) {
|
||||
return writeGeometry(geometry, this.adaptOptions(opt_options));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
@@ -325,249 +476,4 @@ function writePolygonGeometry(geometry, opt_options) {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Read a feature from a GeoJSON Feature source. Only works for Feature or
|
||||
* geometry types. Use {@link module:ol/format/GeoJSON#readFeatures} to read
|
||||
* FeatureCollection source. If feature at source has an id, it will be used
|
||||
* as Feature id by calling {@link module:ol/Feature#setId} internally.
|
||||
*
|
||||
* @function
|
||||
* @param {Document|Node|Object|string} source Source.
|
||||
* @param {module:ol/format/Feature~ReadOptions=} opt_options Read options.
|
||||
* @return {module:ol/Feature} Feature.
|
||||
* @api
|
||||
*/
|
||||
GeoJSON.prototype.readFeature;
|
||||
|
||||
|
||||
/**
|
||||
* Read all features from a GeoJSON source. Works for all GeoJSON types.
|
||||
* If the source includes only geometries, features will be created with those
|
||||
* geometries.
|
||||
*
|
||||
* @function
|
||||
* @param {Document|Node|Object|string} source Source.
|
||||
* @param {module:ol/format/Feature~ReadOptions=} opt_options Read options.
|
||||
* @return {Array.<module:ol/Feature>} Features.
|
||||
* @api
|
||||
*/
|
||||
GeoJSON.prototype.readFeatures;
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
GeoJSON.prototype.readFeatureFromObject = function(object, opt_options) {
|
||||
/**
|
||||
* @type {GeoJSONFeature}
|
||||
*/
|
||||
let geoJSONFeature = null;
|
||||
if (object.type === 'Feature') {
|
||||
geoJSONFeature = /** @type {GeoJSONFeature} */ (object);
|
||||
} else {
|
||||
geoJSONFeature = /** @type {GeoJSONFeature} */ ({
|
||||
type: 'Feature',
|
||||
geometry: /** @type {GeoJSONGeometry|GeoJSONGeometryCollection} */ (object)
|
||||
});
|
||||
}
|
||||
|
||||
const geometry = readGeometry(geoJSONFeature.geometry, opt_options);
|
||||
const feature = new Feature();
|
||||
if (this.geometryName_) {
|
||||
feature.setGeometryName(this.geometryName_);
|
||||
} else if (this.extractGeometryName_ && geoJSONFeature.geometry_name !== undefined) {
|
||||
feature.setGeometryName(geoJSONFeature.geometry_name);
|
||||
}
|
||||
feature.setGeometry(geometry);
|
||||
if (geoJSONFeature.id !== undefined) {
|
||||
feature.setId(geoJSONFeature.id);
|
||||
}
|
||||
if (geoJSONFeature.properties) {
|
||||
feature.setProperties(geoJSONFeature.properties);
|
||||
}
|
||||
return feature;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
GeoJSON.prototype.readFeaturesFromObject = function(object, opt_options) {
|
||||
const geoJSONObject = /** @type {GeoJSONObject} */ (object);
|
||||
/** @type {Array.<module:ol/Feature>} */
|
||||
let features = null;
|
||||
if (geoJSONObject.type === 'FeatureCollection') {
|
||||
const geoJSONFeatureCollection = /** @type {GeoJSONFeatureCollection} */ (object);
|
||||
features = [];
|
||||
const geoJSONFeatures = geoJSONFeatureCollection.features;
|
||||
for (let i = 0, ii = geoJSONFeatures.length; i < ii; ++i) {
|
||||
features.push(this.readFeatureFromObject(geoJSONFeatures[i], opt_options));
|
||||
}
|
||||
} else {
|
||||
features = [this.readFeatureFromObject(object, opt_options)];
|
||||
}
|
||||
return features;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Read a geometry from a GeoJSON source.
|
||||
*
|
||||
* @function
|
||||
* @param {Document|Node|Object|string} source Source.
|
||||
* @param {module:ol/format/Feature~ReadOptions=} opt_options Read options.
|
||||
* @return {module:ol/geom/Geometry} Geometry.
|
||||
* @api
|
||||
*/
|
||||
GeoJSON.prototype.readGeometry;
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
GeoJSON.prototype.readGeometryFromObject = function(object, opt_options) {
|
||||
return readGeometry(/** @type {GeoJSONGeometry} */ (object), opt_options);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Read the projection from a GeoJSON source.
|
||||
*
|
||||
* @function
|
||||
* @param {Document|Node|Object|string} source Source.
|
||||
* @return {module:ol/proj/Projection} Projection.
|
||||
* @api
|
||||
*/
|
||||
GeoJSON.prototype.readProjection;
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
GeoJSON.prototype.readProjectionFromObject = function(object) {
|
||||
const geoJSONObject = /** @type {GeoJSONObject} */ (object);
|
||||
const crs = geoJSONObject.crs;
|
||||
let projection;
|
||||
if (crs) {
|
||||
if (crs.type == 'name') {
|
||||
projection = getProjection(crs.properties.name);
|
||||
} else {
|
||||
assert(false, 36); // Unknown SRS type
|
||||
}
|
||||
} else {
|
||||
projection = this.dataProjection;
|
||||
}
|
||||
return (
|
||||
/** @type {module:ol/proj/Projection} */ (projection)
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Encode a feature as a GeoJSON Feature string.
|
||||
*
|
||||
* @function
|
||||
* @param {module:ol/Feature} feature Feature.
|
||||
* @param {module:ol/format/Feature~WriteOptions=} opt_options Write options.
|
||||
* @return {string} GeoJSON.
|
||||
* @override
|
||||
* @api
|
||||
*/
|
||||
GeoJSON.prototype.writeFeature;
|
||||
|
||||
|
||||
/**
|
||||
* Encode a feature as a GeoJSON Feature object.
|
||||
*
|
||||
* @param {module:ol/Feature} feature Feature.
|
||||
* @param {module:ol/format/Feature~WriteOptions=} opt_options Write options.
|
||||
* @return {GeoJSONFeature} Object.
|
||||
* @override
|
||||
* @api
|
||||
*/
|
||||
GeoJSON.prototype.writeFeatureObject = function(feature, opt_options) {
|
||||
opt_options = this.adaptOptions(opt_options);
|
||||
|
||||
const object = /** @type {GeoJSONFeature} */ ({
|
||||
'type': 'Feature'
|
||||
});
|
||||
const id = feature.getId();
|
||||
if (id !== undefined) {
|
||||
object.id = id;
|
||||
}
|
||||
const geometry = feature.getGeometry();
|
||||
if (geometry) {
|
||||
object.geometry = writeGeometry(geometry, opt_options);
|
||||
} else {
|
||||
object.geometry = null;
|
||||
}
|
||||
const properties = feature.getProperties();
|
||||
delete properties[feature.getGeometryName()];
|
||||
if (!isEmpty(properties)) {
|
||||
object.properties = properties;
|
||||
} else {
|
||||
object.properties = null;
|
||||
}
|
||||
return object;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Encode an array of features as GeoJSON.
|
||||
*
|
||||
* @function
|
||||
* @param {Array.<module:ol/Feature>} features Features.
|
||||
* @param {module:ol/format/Feature~WriteOptions=} opt_options Write options.
|
||||
* @return {string} GeoJSON.
|
||||
* @api
|
||||
*/
|
||||
GeoJSON.prototype.writeFeatures;
|
||||
|
||||
|
||||
/**
|
||||
* Encode an array of features as a GeoJSON object.
|
||||
*
|
||||
* @param {Array.<module:ol/Feature>} features Features.
|
||||
* @param {module:ol/format/Feature~WriteOptions=} opt_options Write options.
|
||||
* @return {GeoJSONFeatureCollection} GeoJSON Object.
|
||||
* @override
|
||||
* @api
|
||||
*/
|
||||
GeoJSON.prototype.writeFeaturesObject = function(features, opt_options) {
|
||||
opt_options = this.adaptOptions(opt_options);
|
||||
const objects = [];
|
||||
for (let i = 0, ii = features.length; i < ii; ++i) {
|
||||
objects.push(this.writeFeatureObject(features[i], opt_options));
|
||||
}
|
||||
return /** @type {GeoJSONFeatureCollection} */ ({
|
||||
type: 'FeatureCollection',
|
||||
features: objects
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Encode a geometry as a GeoJSON string.
|
||||
*
|
||||
* @function
|
||||
* @param {module:ol/geom/Geometry} geometry Geometry.
|
||||
* @param {module:ol/format/Feature~WriteOptions=} opt_options Write options.
|
||||
* @return {string} GeoJSON.
|
||||
* @api
|
||||
*/
|
||||
GeoJSON.prototype.writeGeometry;
|
||||
|
||||
|
||||
/**
|
||||
* Encode a geometry as a GeoJSON object.
|
||||
*
|
||||
* @param {module:ol/geom/Geometry} geometry Geometry.
|
||||
* @param {module:ol/format/Feature~WriteOptions=} opt_options Write options.
|
||||
* @return {GeoJSONGeometry|GeoJSONGeometryCollection} Object.
|
||||
* @override
|
||||
* @api
|
||||
*/
|
||||
GeoJSON.prototype.writeGeometryObject = function(geometry, opt_options) {
|
||||
return writeGeometry(geometry, this.adaptOptions(opt_options));
|
||||
};
|
||||
export default GeoJSON;
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
/**
|
||||
* @module ol/format/IGC
|
||||
*/
|
||||
import {inherits} from '../util.js';
|
||||
import Feature from '../Feature.js';
|
||||
import {transformWithOptions} from '../format/Feature.js';
|
||||
import TextFeature from '../format/TextFeature.js';
|
||||
@@ -19,44 +18,6 @@ const IGCZ = {
|
||||
NONE: 'none'
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @typedef {Object} Options
|
||||
* @property {IGCZ|string} [altitudeMode='none'] Altitude mode. Possible
|
||||
* values are `'barometric'`, `'gps'`, and `'none'`.
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* @classdesc
|
||||
* Feature format for `*.igc` flight recording files.
|
||||
*
|
||||
* @constructor
|
||||
* @extends {module:ol/format/TextFeature}
|
||||
* @param {module:ol/format/IGC~Options=} opt_options Options.
|
||||
* @api
|
||||
*/
|
||||
const IGC = function(opt_options) {
|
||||
|
||||
const options = opt_options ? opt_options : {};
|
||||
|
||||
TextFeature.call(this);
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
this.dataProjection = getProjection('EPSG:4326');
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {IGCZ}
|
||||
*/
|
||||
this.altitudeMode_ = options.altitudeMode ? options.altitudeMode : IGCZ.NONE;
|
||||
};
|
||||
|
||||
inherits(IGC, TextFeature);
|
||||
|
||||
|
||||
/**
|
||||
* @const
|
||||
* @type {RegExp}
|
||||
@@ -89,154 +50,154 @@ const NEWLINE_RE = /\r\n|\r|\n/;
|
||||
|
||||
|
||||
/**
|
||||
* Read the feature from the IGC source.
|
||||
*
|
||||
* @function
|
||||
* @param {Document|Node|Object|string} source Source.
|
||||
* @param {module:ol/format/Feature~ReadOptions=} opt_options Read options.
|
||||
* @return {module:ol/Feature} Feature.
|
||||
* @api
|
||||
* @typedef {Object} Options
|
||||
* @property {IGCZ|string} [altitudeMode='none'] Altitude mode. Possible
|
||||
* values are `'barometric'`, `'gps'`, and `'none'`.
|
||||
*/
|
||||
IGC.prototype.readFeature;
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @classdesc
|
||||
* Feature format for `*.igc` flight recording files.
|
||||
*
|
||||
* As IGC sources contain a single feature,
|
||||
* {@link module:ol/format/IGC~IGC#readFeatures} will return the feature in an
|
||||
* array
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
IGC.prototype.readFeatureFromText = function(text, opt_options) {
|
||||
const altitudeMode = this.altitudeMode_;
|
||||
const lines = text.split(NEWLINE_RE);
|
||||
/** @type {Object.<string, string>} */
|
||||
const properties = {};
|
||||
const flatCoordinates = [];
|
||||
let year = 2000;
|
||||
let month = 0;
|
||||
let day = 1;
|
||||
let lastDateTime = -1;
|
||||
let i, ii;
|
||||
for (i = 0, ii = lines.length; i < ii; ++i) {
|
||||
const line = lines[i];
|
||||
let m;
|
||||
if (line.charAt(0) == 'B') {
|
||||
m = B_RECORD_RE.exec(line);
|
||||
if (m) {
|
||||
const hour = parseInt(m[1], 10);
|
||||
const minute = parseInt(m[2], 10);
|
||||
const second = parseInt(m[3], 10);
|
||||
let y = parseInt(m[4], 10) + parseInt(m[5], 10) / 60000;
|
||||
if (m[6] == 'S') {
|
||||
y = -y;
|
||||
}
|
||||
let x = parseInt(m[7], 10) + parseInt(m[8], 10) / 60000;
|
||||
if (m[9] == 'W') {
|
||||
x = -x;
|
||||
}
|
||||
flatCoordinates.push(x, y);
|
||||
if (altitudeMode != IGCZ.NONE) {
|
||||
let z;
|
||||
if (altitudeMode == IGCZ.GPS) {
|
||||
z = parseInt(m[11], 10);
|
||||
} else if (altitudeMode == IGCZ.BAROMETRIC) {
|
||||
z = parseInt(m[12], 10);
|
||||
} else {
|
||||
z = 0;
|
||||
}
|
||||
flatCoordinates.push(z);
|
||||
}
|
||||
let dateTime = Date.UTC(year, month, day, hour, minute, second);
|
||||
// Detect UTC midnight wrap around.
|
||||
if (dateTime < lastDateTime) {
|
||||
dateTime = Date.UTC(year, month, day + 1, hour, minute, second);
|
||||
}
|
||||
flatCoordinates.push(dateTime / 1000);
|
||||
lastDateTime = dateTime;
|
||||
}
|
||||
} else if (line.charAt(0) == 'H') {
|
||||
m = HFDTE_RECORD_RE.exec(line);
|
||||
if (m) {
|
||||
day = parseInt(m[1], 10);
|
||||
month = parseInt(m[2], 10) - 1;
|
||||
year = 2000 + parseInt(m[3], 10);
|
||||
} else {
|
||||
m = H_RECORD_RE.exec(line);
|
||||
class IGC extends TextFeature {
|
||||
|
||||
/**
|
||||
* @param {module:ol/format/IGC~Options=} opt_options Options.
|
||||
*/
|
||||
constructor(opt_options) {
|
||||
super();
|
||||
|
||||
const options = opt_options ? opt_options : {};
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
this.dataProjection = getProjection('EPSG:4326');
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {IGCZ}
|
||||
*/
|
||||
this.altitudeMode_ = options.altitudeMode ? options.altitudeMode : IGCZ.NONE;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
readFeatureFromText(text, opt_options) {
|
||||
const altitudeMode = this.altitudeMode_;
|
||||
const lines = text.split(NEWLINE_RE);
|
||||
/** @type {Object.<string, string>} */
|
||||
const properties = {};
|
||||
const flatCoordinates = [];
|
||||
let year = 2000;
|
||||
let month = 0;
|
||||
let day = 1;
|
||||
let lastDateTime = -1;
|
||||
let i, ii;
|
||||
for (i = 0, ii = lines.length; i < ii; ++i) {
|
||||
const line = lines[i];
|
||||
let m;
|
||||
if (line.charAt(0) == 'B') {
|
||||
m = B_RECORD_RE.exec(line);
|
||||
if (m) {
|
||||
properties[m[1]] = m[2].trim();
|
||||
const hour = parseInt(m[1], 10);
|
||||
const minute = parseInt(m[2], 10);
|
||||
const second = parseInt(m[3], 10);
|
||||
let y = parseInt(m[4], 10) + parseInt(m[5], 10) / 60000;
|
||||
if (m[6] == 'S') {
|
||||
y = -y;
|
||||
}
|
||||
let x = parseInt(m[7], 10) + parseInt(m[8], 10) / 60000;
|
||||
if (m[9] == 'W') {
|
||||
x = -x;
|
||||
}
|
||||
flatCoordinates.push(x, y);
|
||||
if (altitudeMode != IGCZ.NONE) {
|
||||
let z;
|
||||
if (altitudeMode == IGCZ.GPS) {
|
||||
z = parseInt(m[11], 10);
|
||||
} else if (altitudeMode == IGCZ.BAROMETRIC) {
|
||||
z = parseInt(m[12], 10);
|
||||
} else {
|
||||
z = 0;
|
||||
}
|
||||
flatCoordinates.push(z);
|
||||
}
|
||||
let dateTime = Date.UTC(year, month, day, hour, minute, second);
|
||||
// Detect UTC midnight wrap around.
|
||||
if (dateTime < lastDateTime) {
|
||||
dateTime = Date.UTC(year, month, day + 1, hour, minute, second);
|
||||
}
|
||||
flatCoordinates.push(dateTime / 1000);
|
||||
lastDateTime = dateTime;
|
||||
}
|
||||
} else if (line.charAt(0) == 'H') {
|
||||
m = HFDTE_RECORD_RE.exec(line);
|
||||
if (m) {
|
||||
day = parseInt(m[1], 10);
|
||||
month = parseInt(m[2], 10) - 1;
|
||||
year = 2000 + parseInt(m[3], 10);
|
||||
} else {
|
||||
m = H_RECORD_RE.exec(line);
|
||||
if (m) {
|
||||
properties[m[1]] = m[2].trim();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (flatCoordinates.length === 0) {
|
||||
return null;
|
||||
}
|
||||
const layout = altitudeMode == IGCZ.NONE ? GeometryLayout.XYM : GeometryLayout.XYZM;
|
||||
const lineString = new LineString(flatCoordinates, layout);
|
||||
const feature = new Feature(transformWithOptions(lineString, false, opt_options));
|
||||
feature.setProperties(properties);
|
||||
return feature;
|
||||
}
|
||||
if (flatCoordinates.length === 0) {
|
||||
return null;
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
readFeaturesFromText(text, opt_options) {
|
||||
const feature = this.readFeatureFromText(text, opt_options);
|
||||
if (feature) {
|
||||
return [feature];
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
const layout = altitudeMode == IGCZ.NONE ? GeometryLayout.XYM : GeometryLayout.XYZM;
|
||||
const lineString = new LineString(flatCoordinates, layout);
|
||||
const feature = new Feature(transformWithOptions(lineString, false, opt_options));
|
||||
feature.setProperties(properties);
|
||||
return feature;
|
||||
};
|
||||
|
||||
/**
|
||||
* Not implemented.
|
||||
* @inheritDoc
|
||||
*/
|
||||
writeFeatureText(feature, opt_options) {}
|
||||
|
||||
/**
|
||||
* Read the feature from the source. As IGC sources contain a single
|
||||
* feature, this will return the feature in an array.
|
||||
*
|
||||
* @function
|
||||
* @param {Document|Node|Object|string} source Source.
|
||||
* @param {module:ol/format/Feature~ReadOptions=} opt_options Read options.
|
||||
* @return {Array.<module:ol/Feature>} Features.
|
||||
* @api
|
||||
*/
|
||||
IGC.prototype.readFeatures;
|
||||
/**
|
||||
* Not implemented.
|
||||
* @inheritDoc
|
||||
*/
|
||||
writeFeaturesText(features, opt_options) {}
|
||||
|
||||
/**
|
||||
* Not implemented.
|
||||
* @inheritDoc
|
||||
*/
|
||||
writeGeometryText(geometry, opt_options) {}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
IGC.prototype.readFeaturesFromText = function(text, opt_options) {
|
||||
const feature = this.readFeatureFromText(text, opt_options);
|
||||
if (feature) {
|
||||
return [feature];
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
};
|
||||
/**
|
||||
* Not implemented.
|
||||
* @inheritDoc
|
||||
*/
|
||||
readGeometryFromText(text, opt_options) {}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Read the projection from the IGC source.
|
||||
*
|
||||
* @function
|
||||
* @param {Document|Node|Object|string} source Source.
|
||||
* @return {module:ol/proj/Projection} Projection.
|
||||
* @api
|
||||
*/
|
||||
IGC.prototype.readProjection;
|
||||
|
||||
|
||||
/**
|
||||
* Not implemented.
|
||||
* @inheritDoc
|
||||
*/
|
||||
IGC.prototype.writeFeatureText = function(feature, opt_options) {};
|
||||
|
||||
|
||||
/**
|
||||
* Not implemented.
|
||||
* @inheritDoc
|
||||
*/
|
||||
IGC.prototype.writeFeaturesText = function(features, opt_options) {};
|
||||
|
||||
|
||||
/**
|
||||
* Not implemented.
|
||||
* @inheritDoc
|
||||
*/
|
||||
IGC.prototype.writeGeometryText = function(geometry, opt_options) {};
|
||||
|
||||
|
||||
/**
|
||||
* Not implemented.
|
||||
* @inheritDoc
|
||||
*/
|
||||
IGC.prototype.readGeometryFromText = function(text, opt_options) {};
|
||||
export default IGC;
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
/**
|
||||
* @module ol/format/JSONFeature
|
||||
*/
|
||||
import {inherits} from '../util.js';
|
||||
import FeatureFormat from '../format/Feature.js';
|
||||
import FormatType from '../format/FormatType.js';
|
||||
|
||||
@@ -11,15 +10,167 @@ import FormatType from '../format/FormatType.js';
|
||||
* instantiated in apps.
|
||||
* Base class for JSON feature formats.
|
||||
*
|
||||
* @constructor
|
||||
* @abstract
|
||||
* @extends {module:ol/format/Feature}
|
||||
*/
|
||||
const JSONFeature = function() {
|
||||
FeatureFormat.call(this);
|
||||
};
|
||||
class JSONFeature extends FeatureFormat {
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
|
||||
inherits(JSONFeature, FeatureFormat);
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
getType() {
|
||||
return FormatType.JSON;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a feature. Only works for a single feature. Use `readFeatures` to
|
||||
* read a feature collection.
|
||||
*
|
||||
* @param {ArrayBuffer|Document|Node|Object|string} source Source.
|
||||
* @param {module:ol/format/Feature~ReadOptions=} opt_options Read options.
|
||||
* @return {module:ol/Feature} Feature.
|
||||
* @api
|
||||
*/
|
||||
readFeature(source, opt_options) {
|
||||
return this.readFeatureFromObject(
|
||||
getObject(source), this.getReadOptions(source, opt_options));
|
||||
}
|
||||
|
||||
/**
|
||||
* Read all features. Works with both a single feature and a feature
|
||||
* collection.
|
||||
*
|
||||
* @param {ArrayBuffer|Document|Node|Object|string} source Source.
|
||||
* @param {module:ol/format/Feature~ReadOptions=} opt_options Read options.
|
||||
* @return {Array.<module:ol/Feature>} Features.
|
||||
* @api
|
||||
*/
|
||||
readFeatures(source, opt_options) {
|
||||
return this.readFeaturesFromObject(
|
||||
getObject(source), this.getReadOptions(source, opt_options));
|
||||
}
|
||||
|
||||
/**
|
||||
* @abstract
|
||||
* @param {Object} object Object.
|
||||
* @param {module:ol/format/Feature~ReadOptions=} opt_options Read options.
|
||||
* @protected
|
||||
* @return {module:ol/Feature} Feature.
|
||||
*/
|
||||
readFeatureFromObject(object, opt_options) {}
|
||||
|
||||
/**
|
||||
* @abstract
|
||||
* @param {Object} object Object.
|
||||
* @param {module:ol/format/Feature~ReadOptions=} opt_options Read options.
|
||||
* @protected
|
||||
* @return {Array.<module:ol/Feature>} Features.
|
||||
*/
|
||||
readFeaturesFromObject(object, opt_options) {}
|
||||
|
||||
/**
|
||||
* Read a geometry.
|
||||
*
|
||||
* @param {ArrayBuffer|Document|Node|Object|string} source Source.
|
||||
* @param {module:ol/format/Feature~ReadOptions=} opt_options Read options.
|
||||
* @return {module:ol/geom/Geometry} Geometry.
|
||||
* @api
|
||||
*/
|
||||
readGeometry(source, opt_options) {
|
||||
return this.readGeometryFromObject(
|
||||
getObject(source), this.getReadOptions(source, opt_options));
|
||||
}
|
||||
|
||||
/**
|
||||
* @abstract
|
||||
* @param {Object} object Object.
|
||||
* @param {module:ol/format/Feature~ReadOptions=} opt_options Read options.
|
||||
* @protected
|
||||
* @return {module:ol/geom/Geometry} Geometry.
|
||||
*/
|
||||
readGeometryFromObject(object, opt_options) {}
|
||||
|
||||
/**
|
||||
* Read the projection.
|
||||
*
|
||||
* @param {ArrayBuffer|Document|Node|Object|string} source Source.
|
||||
* @return {module:ol/proj/Projection} Projection.
|
||||
* @api
|
||||
*/
|
||||
readProjection(source) {
|
||||
return this.readProjectionFromObject(getObject(source));
|
||||
}
|
||||
|
||||
/**
|
||||
* @abstract
|
||||
* @param {Object} object Object.
|
||||
* @protected
|
||||
* @return {module:ol/proj/Projection} Projection.
|
||||
*/
|
||||
readProjectionFromObject(object) {}
|
||||
|
||||
/**
|
||||
* Encode a feature as string.
|
||||
*
|
||||
* @param {module:ol/Feature} feature Feature.
|
||||
* @param {module:ol/format/Feature~WriteOptions=} opt_options Write options.
|
||||
* @return {string} Encoded feature.
|
||||
* @api
|
||||
*/
|
||||
writeFeature(feature, opt_options) {
|
||||
return JSON.stringify(this.writeFeatureObject(feature, opt_options));
|
||||
}
|
||||
|
||||
/**
|
||||
* @abstract
|
||||
* @param {module:ol/Feature} feature Feature.
|
||||
* @param {module:ol/format/Feature~WriteOptions=} opt_options Write options.
|
||||
* @return {Object} Object.
|
||||
*/
|
||||
writeFeatureObject(feature, opt_options) {}
|
||||
|
||||
/**
|
||||
* Encode an array of features as string.
|
||||
*
|
||||
* @param {Array.<module:ol/Feature>} features Features.
|
||||
* @param {module:ol/format/Feature~WriteOptions=} opt_options Write options.
|
||||
* @return {string} Encoded features.
|
||||
* @api
|
||||
*/
|
||||
writeFeatures(features, opt_options) {
|
||||
return JSON.stringify(this.writeFeaturesObject(features, opt_options));
|
||||
}
|
||||
|
||||
/**
|
||||
* @abstract
|
||||
* @param {Array.<module:ol/Feature>} features Features.
|
||||
* @param {module:ol/format/Feature~WriteOptions=} opt_options Write options.
|
||||
* @return {Object} Object.
|
||||
*/
|
||||
writeFeaturesObject(features, opt_options) {}
|
||||
|
||||
/**
|
||||
* Encode a geometry as string.
|
||||
*
|
||||
* @param {module:ol/geom/Geometry} geometry Geometry.
|
||||
* @param {module:ol/format/Feature~WriteOptions=} opt_options Write options.
|
||||
* @return {string} Encoded geometry.
|
||||
* @api
|
||||
*/
|
||||
writeGeometry(geometry, opt_options) {
|
||||
return JSON.stringify(this.writeGeometryObject(geometry, opt_options));
|
||||
}
|
||||
|
||||
/**
|
||||
* @abstract
|
||||
* @param {module:ol/geom/Geometry} geometry Geometry.
|
||||
* @param {module:ol/format/Feature~WriteOptions=} opt_options Write options.
|
||||
* @return {Object} Object.
|
||||
*/
|
||||
writeGeometryObject(geometry, opt_options) {}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
@@ -38,135 +189,4 @@ function getObject(source) {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
JSONFeature.prototype.getType = function() {
|
||||
return FormatType.JSON;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
JSONFeature.prototype.readFeature = function(source, opt_options) {
|
||||
return this.readFeatureFromObject(
|
||||
getObject(source), this.getReadOptions(source, opt_options));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
JSONFeature.prototype.readFeatures = function(source, opt_options) {
|
||||
return this.readFeaturesFromObject(
|
||||
getObject(source), this.getReadOptions(source, opt_options));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @abstract
|
||||
* @param {Object} object Object.
|
||||
* @param {module:ol/format/Feature~ReadOptions=} opt_options Read options.
|
||||
* @protected
|
||||
* @return {module:ol/Feature} Feature.
|
||||
*/
|
||||
JSONFeature.prototype.readFeatureFromObject = function(object, opt_options) {};
|
||||
|
||||
|
||||
/**
|
||||
* @abstract
|
||||
* @param {Object} object Object.
|
||||
* @param {module:ol/format/Feature~ReadOptions=} opt_options Read options.
|
||||
* @protected
|
||||
* @return {Array.<module:ol/Feature>} Features.
|
||||
*/
|
||||
JSONFeature.prototype.readFeaturesFromObject = function(object, opt_options) {};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
JSONFeature.prototype.readGeometry = function(source, opt_options) {
|
||||
return this.readGeometryFromObject(
|
||||
getObject(source), this.getReadOptions(source, opt_options));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @abstract
|
||||
* @param {Object} object Object.
|
||||
* @param {module:ol/format/Feature~ReadOptions=} opt_options Read options.
|
||||
* @protected
|
||||
* @return {module:ol/geom/Geometry} Geometry.
|
||||
*/
|
||||
JSONFeature.prototype.readGeometryFromObject = function(object, opt_options) {};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
JSONFeature.prototype.readProjection = function(source) {
|
||||
return this.readProjectionFromObject(getObject(source));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @abstract
|
||||
* @param {Object} object Object.
|
||||
* @protected
|
||||
* @return {module:ol/proj/Projection} Projection.
|
||||
*/
|
||||
JSONFeature.prototype.readProjectionFromObject = function(object) {};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
JSONFeature.prototype.writeFeature = function(feature, opt_options) {
|
||||
return JSON.stringify(this.writeFeatureObject(feature, opt_options));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @abstract
|
||||
* @param {module:ol/Feature} feature Feature.
|
||||
* @param {module:ol/format/Feature~WriteOptions=} opt_options Write options.
|
||||
* @return {Object} Object.
|
||||
*/
|
||||
JSONFeature.prototype.writeFeatureObject = function(feature, opt_options) {};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
JSONFeature.prototype.writeFeatures = function(features, opt_options) {
|
||||
return JSON.stringify(this.writeFeaturesObject(features, opt_options));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @abstract
|
||||
* @param {Array.<module:ol/Feature>} features Features.
|
||||
* @param {module:ol/format/Feature~WriteOptions=} opt_options Write options.
|
||||
* @return {Object} Object.
|
||||
*/
|
||||
JSONFeature.prototype.writeFeaturesObject = function(features, opt_options) {};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
JSONFeature.prototype.writeGeometry = function(geometry, opt_options) {
|
||||
return JSON.stringify(this.writeGeometryObject(geometry, opt_options));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @abstract
|
||||
* @param {module:ol/geom/Geometry} geometry Geometry.
|
||||
* @param {module:ol/format/Feature~WriteOptions=} opt_options Write options.
|
||||
* @return {Object} Object.
|
||||
*/
|
||||
JSONFeature.prototype.writeGeometryObject = function(geometry, opt_options) {};
|
||||
export default JSONFeature;
|
||||
|
||||
1195
src/ol/format/KML.js
1195
src/ol/format/KML.js
File diff suppressed because it is too large
Load Diff
@@ -3,7 +3,6 @@
|
||||
*/
|
||||
//FIXME Implement projection handling
|
||||
|
||||
import {inherits} from '../util.js';
|
||||
import {assert} from '../asserts.js';
|
||||
import PBF from 'pbf';
|
||||
import FeatureFormat, {transformWithOptions} from '../format/Feature.js';
|
||||
@@ -42,61 +41,282 @@ import RenderFeature from '../render/Feature.js';
|
||||
* @classdesc
|
||||
* Feature format for reading data in the Mapbox MVT format.
|
||||
*
|
||||
* @constructor
|
||||
* @extends {module:ol/format/Feature}
|
||||
* @param {module:ol/format/MVT~Options=} opt_options Options.
|
||||
* @api
|
||||
*/
|
||||
const MVT = function(opt_options) {
|
||||
|
||||
FeatureFormat.call(this);
|
||||
|
||||
const options = opt_options ? opt_options : {};
|
||||
class MVT extends FeatureFormat {
|
||||
|
||||
/**
|
||||
* @type {module:ol/proj/Projection}
|
||||
* @param {module:ol/format/MVT~Options=} opt_options Options.
|
||||
*/
|
||||
this.dataProjection = new Projection({
|
||||
code: '',
|
||||
units: Units.TILE_PIXELS
|
||||
});
|
||||
constructor(opt_options) {
|
||||
super();
|
||||
|
||||
const options = opt_options ? opt_options : {};
|
||||
|
||||
/**
|
||||
* @type {module:ol/proj/Projection}
|
||||
*/
|
||||
this.dataProjection = new Projection({
|
||||
code: '',
|
||||
units: Units.TILE_PIXELS
|
||||
});
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {function((module:ol/geom/Geometry|Object.<string,*>)=)|
|
||||
* function(module:ol/geom/GeometryType,Array.<number>,
|
||||
* (Array.<number>|Array.<Array.<number>>),Object.<string,*>,number)}
|
||||
*/
|
||||
this.featureClass_ = options.featureClass ?
|
||||
options.featureClass : RenderFeature;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {string|undefined}
|
||||
*/
|
||||
this.geometryName_ = options.geometryName;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {string}
|
||||
*/
|
||||
this.layerName_ = options.layerName ? options.layerName : 'layer';
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {Array.<string>}
|
||||
*/
|
||||
this.layers_ = options.layers ? options.layers : null;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {module:ol/extent~Extent}
|
||||
*/
|
||||
this.extent_ = null;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the raw geometry from the pbf offset stored in a raw feature's geometry
|
||||
* property.
|
||||
* @suppress {missingProperties}
|
||||
* @param {Object} pbf PBF.
|
||||
* @param {Object} feature Raw feature.
|
||||
* @param {Array.<number>} flatCoordinates Array to store flat coordinates in.
|
||||
* @param {Array.<number>} ends Array to store ends in.
|
||||
* @private
|
||||
*/
|
||||
readRawGeometry_(pbf, feature, flatCoordinates, ends) {
|
||||
pbf.pos = feature.geometry;
|
||||
|
||||
const end = pbf.readVarint() + pbf.pos;
|
||||
let cmd = 1;
|
||||
let length = 0;
|
||||
let x = 0;
|
||||
let y = 0;
|
||||
let coordsLen = 0;
|
||||
let currentEnd = 0;
|
||||
|
||||
while (pbf.pos < end) {
|
||||
if (!length) {
|
||||
const cmdLen = pbf.readVarint();
|
||||
cmd = cmdLen & 0x7;
|
||||
length = cmdLen >> 3;
|
||||
}
|
||||
|
||||
length--;
|
||||
|
||||
if (cmd === 1 || cmd === 2) {
|
||||
x += pbf.readSVarint();
|
||||
y += pbf.readSVarint();
|
||||
|
||||
if (cmd === 1) { // moveTo
|
||||
if (coordsLen > currentEnd) {
|
||||
ends.push(coordsLen);
|
||||
currentEnd = coordsLen;
|
||||
}
|
||||
}
|
||||
|
||||
flatCoordinates.push(x, y);
|
||||
coordsLen += 2;
|
||||
|
||||
} else if (cmd === 7) {
|
||||
|
||||
if (coordsLen > currentEnd) {
|
||||
// close polygon
|
||||
flatCoordinates.push(
|
||||
flatCoordinates[currentEnd], flatCoordinates[currentEnd + 1]);
|
||||
coordsLen += 2;
|
||||
}
|
||||
|
||||
} else {
|
||||
assert(false, 59); // Invalid command found in the PBF
|
||||
}
|
||||
}
|
||||
|
||||
if (coordsLen > currentEnd) {
|
||||
ends.push(coordsLen);
|
||||
currentEnd = coordsLen;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {function((module:ol/geom/Geometry|Object.<string,*>)=)|
|
||||
* function(module:ol/geom/GeometryType,Array.<number>,
|
||||
* (Array.<number>|Array.<Array.<number>>),Object.<string,*>,number)}
|
||||
* @param {Object} pbf PBF
|
||||
* @param {Object} rawFeature Raw Mapbox feature.
|
||||
* @param {module:ol/format/Feature~ReadOptions=} opt_options Read options.
|
||||
* @return {module:ol/Feature|module:ol/render/Feature} Feature.
|
||||
*/
|
||||
this.featureClass_ = options.featureClass ?
|
||||
options.featureClass : RenderFeature;
|
||||
createFeature_(pbf, rawFeature, opt_options) {
|
||||
const type = rawFeature.type;
|
||||
if (type === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let feature;
|
||||
const id = rawFeature.id;
|
||||
const values = rawFeature.properties;
|
||||
values[this.layerName_] = rawFeature.layer.name;
|
||||
|
||||
const flatCoordinates = [];
|
||||
const ends = [];
|
||||
this.readRawGeometry_(pbf, rawFeature, flatCoordinates, ends);
|
||||
|
||||
const geometryType = getGeometryType(type, ends.length);
|
||||
|
||||
if (this.featureClass_ === RenderFeature) {
|
||||
feature = new this.featureClass_(geometryType, flatCoordinates, ends, values, id);
|
||||
} else {
|
||||
let geom;
|
||||
if (geometryType == GeometryType.POLYGON) {
|
||||
const endss = [];
|
||||
let offset = 0;
|
||||
let prevEndIndex = 0;
|
||||
for (let i = 0, ii = ends.length; i < ii; ++i) {
|
||||
const end = ends[i];
|
||||
if (!linearRingIsClockwise(flatCoordinates, offset, end, 2)) {
|
||||
endss.push(ends.slice(prevEndIndex, i));
|
||||
prevEndIndex = i;
|
||||
}
|
||||
offset = end;
|
||||
}
|
||||
if (endss.length > 1) {
|
||||
geom = new MultiPolygon(flatCoordinates, GeometryLayout.XY, endss);
|
||||
} else {
|
||||
geom = new Polygon(flatCoordinates, GeometryLayout.XY, ends);
|
||||
}
|
||||
} else {
|
||||
geom = geometryType === GeometryType.POINT ? new Point(flatCoordinates, GeometryLayout.XY) :
|
||||
geometryType === GeometryType.LINE_STRING ? new LineString(flatCoordinates, GeometryLayout.XY) :
|
||||
geometryType === GeometryType.POLYGON ? new Polygon(flatCoordinates, GeometryLayout.XY, ends) :
|
||||
geometryType === GeometryType.MULTI_POINT ? new MultiPoint(flatCoordinates, GeometryLayout.XY) :
|
||||
geometryType === GeometryType.MULTI_LINE_STRING ? new MultiLineString(flatCoordinates, GeometryLayout.XY, ends) :
|
||||
null;
|
||||
}
|
||||
feature = new this.featureClass_();
|
||||
if (this.geometryName_) {
|
||||
feature.setGeometryName(this.geometryName_);
|
||||
}
|
||||
const geometry = transformWithOptions(geom, false, this.adaptOptions(opt_options));
|
||||
feature.setGeometry(geometry);
|
||||
feature.setId(id);
|
||||
feature.setProperties(values);
|
||||
}
|
||||
|
||||
return feature;
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {string|undefined}
|
||||
* @inheritDoc
|
||||
* @api
|
||||
*/
|
||||
this.geometryName_ = options.geometryName;
|
||||
getLastExtent() {
|
||||
return this.extent_;
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {string}
|
||||
* @inheritDoc
|
||||
*/
|
||||
this.layerName_ = options.layerName ? options.layerName : 'layer';
|
||||
getType() {
|
||||
return FormatType.ARRAY_BUFFER;
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {Array.<string>}
|
||||
* @inheritDoc
|
||||
* @api
|
||||
*/
|
||||
this.layers_ = options.layers ? options.layers : null;
|
||||
readFeatures(source, opt_options) {
|
||||
const layers = this.layers_;
|
||||
|
||||
const pbf = new PBF(/** @type {ArrayBuffer} */ (source));
|
||||
const pbfLayers = pbf.readFields(layersPBFReader, {});
|
||||
/** @type {Array.<module:ol/Feature|module:ol/render/Feature>} */
|
||||
const features = [];
|
||||
for (const name in pbfLayers) {
|
||||
if (layers && layers.indexOf(name) == -1) {
|
||||
continue;
|
||||
}
|
||||
const pbfLayer = pbfLayers[name];
|
||||
|
||||
for (let i = 0, ii = pbfLayer.length; i < ii; ++i) {
|
||||
const rawFeature = readRawFeature(pbf, pbfLayer, i);
|
||||
features.push(this.createFeature_(pbf, rawFeature));
|
||||
}
|
||||
this.extent_ = pbfLayer ? [0, 0, pbfLayer.extent, pbfLayer.extent] : null;
|
||||
}
|
||||
|
||||
return features;
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {module:ol/extent~Extent}
|
||||
* @inheritDoc
|
||||
* @api
|
||||
*/
|
||||
this.extent_ = null;
|
||||
readProjection(source) {
|
||||
return this.dataProjection;
|
||||
}
|
||||
|
||||
};
|
||||
/**
|
||||
* Sets the layers that features will be read from.
|
||||
* @param {Array.<string>} layers Layers.
|
||||
* @api
|
||||
*/
|
||||
setLayers(layers) {
|
||||
this.layers_ = layers;
|
||||
}
|
||||
|
||||
inherits(MVT, FeatureFormat);
|
||||
/**
|
||||
* Not implemented.
|
||||
* @override
|
||||
*/
|
||||
readFeature() {}
|
||||
|
||||
/**
|
||||
* Not implemented.
|
||||
* @override
|
||||
*/
|
||||
readGeometry() {}
|
||||
|
||||
/**
|
||||
* Not implemented.
|
||||
* @override
|
||||
*/
|
||||
writeFeature() {}
|
||||
|
||||
/**
|
||||
* Not implemented.
|
||||
* @override
|
||||
*/
|
||||
writeGeometry() {}
|
||||
|
||||
/**
|
||||
* Not implemented.
|
||||
* @override
|
||||
*/
|
||||
writeFeatures() {}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
@@ -201,72 +421,6 @@ function readRawFeature(pbf, layer, i) {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Read the raw geometry from the pbf offset stored in a raw feature's geometry
|
||||
* property.
|
||||
* @suppress {missingProperties}
|
||||
* @param {Object} pbf PBF.
|
||||
* @param {Object} feature Raw feature.
|
||||
* @param {Array.<number>} flatCoordinates Array to store flat coordinates in.
|
||||
* @param {Array.<number>} ends Array to store ends in.
|
||||
* @private
|
||||
*/
|
||||
MVT.prototype.readRawGeometry_ = function(pbf, feature, flatCoordinates, ends) {
|
||||
pbf.pos = feature.geometry;
|
||||
|
||||
const end = pbf.readVarint() + pbf.pos;
|
||||
let cmd = 1;
|
||||
let length = 0;
|
||||
let x = 0;
|
||||
let y = 0;
|
||||
let coordsLen = 0;
|
||||
let currentEnd = 0;
|
||||
|
||||
while (pbf.pos < end) {
|
||||
if (!length) {
|
||||
const cmdLen = pbf.readVarint();
|
||||
cmd = cmdLen & 0x7;
|
||||
length = cmdLen >> 3;
|
||||
}
|
||||
|
||||
length--;
|
||||
|
||||
if (cmd === 1 || cmd === 2) {
|
||||
x += pbf.readSVarint();
|
||||
y += pbf.readSVarint();
|
||||
|
||||
if (cmd === 1) { // moveTo
|
||||
if (coordsLen > currentEnd) {
|
||||
ends.push(coordsLen);
|
||||
currentEnd = coordsLen;
|
||||
}
|
||||
}
|
||||
|
||||
flatCoordinates.push(x, y);
|
||||
coordsLen += 2;
|
||||
|
||||
} else if (cmd === 7) {
|
||||
|
||||
if (coordsLen > currentEnd) {
|
||||
// close polygon
|
||||
flatCoordinates.push(
|
||||
flatCoordinates[currentEnd], flatCoordinates[currentEnd + 1]);
|
||||
coordsLen += 2;
|
||||
}
|
||||
|
||||
} else {
|
||||
assert(false, 59); // Invalid command found in the PBF
|
||||
}
|
||||
}
|
||||
|
||||
if (coordsLen > currentEnd) {
|
||||
ends.push(coordsLen);
|
||||
currentEnd = coordsLen;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @suppress {missingProperties}
|
||||
* @param {number} type The raw feature's geometry type
|
||||
@@ -292,168 +446,4 @@ function getGeometryType(type, numEnds) {
|
||||
return geometryType;
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {Object} pbf PBF
|
||||
* @param {Object} rawFeature Raw Mapbox feature.
|
||||
* @param {module:ol/format/Feature~ReadOptions=} opt_options Read options.
|
||||
* @return {module:ol/Feature|module:ol/render/Feature} Feature.
|
||||
*/
|
||||
MVT.prototype.createFeature_ = function(pbf, rawFeature, opt_options) {
|
||||
const type = rawFeature.type;
|
||||
if (type === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let feature;
|
||||
const id = rawFeature.id;
|
||||
const values = rawFeature.properties;
|
||||
values[this.layerName_] = rawFeature.layer.name;
|
||||
|
||||
const flatCoordinates = [];
|
||||
const ends = [];
|
||||
this.readRawGeometry_(pbf, rawFeature, flatCoordinates, ends);
|
||||
|
||||
const geometryType = getGeometryType(type, ends.length);
|
||||
|
||||
if (this.featureClass_ === RenderFeature) {
|
||||
feature = new this.featureClass_(geometryType, flatCoordinates, ends, values, id);
|
||||
} else {
|
||||
let geom;
|
||||
if (geometryType == GeometryType.POLYGON) {
|
||||
const endss = [];
|
||||
let offset = 0;
|
||||
let prevEndIndex = 0;
|
||||
for (let i = 0, ii = ends.length; i < ii; ++i) {
|
||||
const end = ends[i];
|
||||
if (!linearRingIsClockwise(flatCoordinates, offset, end, 2)) {
|
||||
endss.push(ends.slice(prevEndIndex, i));
|
||||
prevEndIndex = i;
|
||||
}
|
||||
offset = end;
|
||||
}
|
||||
if (endss.length > 1) {
|
||||
geom = new MultiPolygon(flatCoordinates, GeometryLayout.XY, endss);
|
||||
} else {
|
||||
geom = new Polygon(flatCoordinates, GeometryLayout.XY, ends);
|
||||
}
|
||||
} else {
|
||||
geom = geometryType === GeometryType.POINT ? new Point(flatCoordinates, GeometryLayout.XY) :
|
||||
geometryType === GeometryType.LINE_STRING ? new LineString(flatCoordinates, GeometryLayout.XY) :
|
||||
geometryType === GeometryType.POLYGON ? new Polygon(flatCoordinates, GeometryLayout.XY, ends) :
|
||||
geometryType === GeometryType.MULTI_POINT ? new MultiPoint(flatCoordinates, GeometryLayout.XY) :
|
||||
geometryType === GeometryType.MULTI_LINE_STRING ? new MultiLineString(flatCoordinates, GeometryLayout.XY, ends) :
|
||||
null;
|
||||
}
|
||||
feature = new this.featureClass_();
|
||||
if (this.geometryName_) {
|
||||
feature.setGeometryName(this.geometryName_);
|
||||
}
|
||||
const geometry = transformWithOptions(geom, false, this.adaptOptions(opt_options));
|
||||
feature.setGeometry(geometry);
|
||||
feature.setId(id);
|
||||
feature.setProperties(values);
|
||||
}
|
||||
|
||||
return feature;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @api
|
||||
*/
|
||||
MVT.prototype.getLastExtent = function() {
|
||||
return this.extent_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
MVT.prototype.getType = function() {
|
||||
return FormatType.ARRAY_BUFFER;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @api
|
||||
*/
|
||||
MVT.prototype.readFeatures = function(source, opt_options) {
|
||||
const layers = this.layers_;
|
||||
|
||||
const pbf = new PBF(/** @type {ArrayBuffer} */ (source));
|
||||
const pbfLayers = pbf.readFields(layersPBFReader, {});
|
||||
/** @type {Array.<module:ol/Feature|module:ol/render/Feature>} */
|
||||
const features = [];
|
||||
for (const name in pbfLayers) {
|
||||
if (layers && layers.indexOf(name) == -1) {
|
||||
continue;
|
||||
}
|
||||
const pbfLayer = pbfLayers[name];
|
||||
|
||||
for (let i = 0, ii = pbfLayer.length; i < ii; ++i) {
|
||||
const rawFeature = readRawFeature(pbf, pbfLayer, i);
|
||||
features.push(this.createFeature_(pbf, rawFeature));
|
||||
}
|
||||
this.extent_ = pbfLayer ? [0, 0, pbfLayer.extent, pbfLayer.extent] : null;
|
||||
}
|
||||
|
||||
return features;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @api
|
||||
*/
|
||||
MVT.prototype.readProjection = function(source) {
|
||||
return this.dataProjection;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Sets the layers that features will be read from.
|
||||
* @param {Array.<string>} layers Layers.
|
||||
* @api
|
||||
*/
|
||||
MVT.prototype.setLayers = function(layers) {
|
||||
this.layers_ = layers;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Not implemented.
|
||||
* @override
|
||||
*/
|
||||
MVT.prototype.readFeature = function() {};
|
||||
|
||||
|
||||
/**
|
||||
* Not implemented.
|
||||
* @override
|
||||
*/
|
||||
MVT.prototype.readGeometry = function() {};
|
||||
|
||||
|
||||
/**
|
||||
* Not implemented.
|
||||
* @override
|
||||
*/
|
||||
MVT.prototype.writeFeature = function() {};
|
||||
|
||||
|
||||
/**
|
||||
* Not implemented.
|
||||
* @override
|
||||
*/
|
||||
MVT.prototype.writeGeometry = function() {};
|
||||
|
||||
|
||||
/**
|
||||
* Not implemented.
|
||||
* @override
|
||||
*/
|
||||
MVT.prototype.writeFeatures = function() {};
|
||||
export default MVT;
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
* @module ol/format/OSMXML
|
||||
*/
|
||||
// FIXME add typedef for stack state objects
|
||||
import {inherits} from '../util.js';
|
||||
import {extend} from '../array.js';
|
||||
import Feature from '../Feature.js';
|
||||
import {transformWithOptions} from '../format/Feature.js';
|
||||
@@ -15,26 +14,6 @@ import {isEmpty} from '../obj.js';
|
||||
import {get as getProjection} from '../proj.js';
|
||||
import {pushParseAndPop, makeStructureNS} from '../xml.js';
|
||||
|
||||
/**
|
||||
* @classdesc
|
||||
* Feature format for reading data in the
|
||||
* [OSMXML format](http://wiki.openstreetmap.org/wiki/OSM_XML).
|
||||
*
|
||||
* @constructor
|
||||
* @extends {module:ol/format/XMLFeature}
|
||||
* @api
|
||||
*/
|
||||
const OSMXML = function() {
|
||||
XMLFeature.call(this);
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
this.dataProjection = getProjection('EPSG:4326');
|
||||
};
|
||||
|
||||
inherits(OSMXML, XMLFeature);
|
||||
|
||||
|
||||
/**
|
||||
* @const
|
||||
@@ -65,6 +44,83 @@ const PARSERS = makeStructureNS(
|
||||
});
|
||||
|
||||
|
||||
/**
|
||||
* @classdesc
|
||||
* Feature format for reading data in the
|
||||
* [OSMXML format](http://wiki.openstreetmap.org/wiki/OSM_XML).
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
class OSMXML extends XMLFeature {
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
this.dataProjection = getProjection('EPSG:4326');
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
readFeaturesFromNode(node, opt_options) {
|
||||
const options = this.getReadOptions(node, opt_options);
|
||||
if (node.localName == 'osm') {
|
||||
const state = pushParseAndPop({
|
||||
nodes: {},
|
||||
ways: [],
|
||||
features: []
|
||||
}, PARSERS, node, [options]);
|
||||
// parse nodes in ways
|
||||
for (let j = 0; j < state.ways.length; j++) {
|
||||
const values = /** @type {Object} */ (state.ways[j]);
|
||||
/** @type {Array.<number>} */
|
||||
const flatCoordinates = [];
|
||||
for (let i = 0, ii = values.ndrefs.length; i < ii; i++) {
|
||||
const point = state.nodes[values.ndrefs[i]];
|
||||
extend(flatCoordinates, point);
|
||||
}
|
||||
let geometry;
|
||||
if (values.ndrefs[0] == values.ndrefs[values.ndrefs.length - 1]) {
|
||||
// closed way
|
||||
geometry = new Polygon(flatCoordinates, GeometryLayout.XY, [flatCoordinates.length]);
|
||||
} else {
|
||||
geometry = new LineString(flatCoordinates, GeometryLayout.XY);
|
||||
}
|
||||
transformWithOptions(geometry, false, options);
|
||||
const feature = new Feature(geometry);
|
||||
feature.setId(values.id);
|
||||
feature.setProperties(values.tags);
|
||||
state.features.push(feature);
|
||||
}
|
||||
if (state.features) {
|
||||
return state.features;
|
||||
}
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Not implemented.
|
||||
* @inheritDoc
|
||||
*/
|
||||
writeFeatureNode(feature, opt_options) {}
|
||||
|
||||
/**
|
||||
* Not implemented.
|
||||
* @inheritDoc
|
||||
*/
|
||||
writeFeaturesNode(features, opt_options) {}
|
||||
|
||||
/**
|
||||
* Not implemented.
|
||||
* @inheritDoc
|
||||
*/
|
||||
writeGeometryNode(geometry, opt_options) {}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @const
|
||||
* @type {Object.<string, Object.<string, module:ol/xml~Parser>>}
|
||||
@@ -140,87 +196,4 @@ function readTag(node, objectStack) {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Read all features from an OSM source.
|
||||
*
|
||||
* @function
|
||||
* @param {Document|Node|Object|string} source Source.
|
||||
* @param {module:ol/format/Feature~ReadOptions=} opt_options Read options.
|
||||
* @return {Array.<module:ol/Feature>} Features.
|
||||
* @api
|
||||
*/
|
||||
OSMXML.prototype.readFeatures;
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
OSMXML.prototype.readFeaturesFromNode = function(node, opt_options) {
|
||||
const options = this.getReadOptions(node, opt_options);
|
||||
if (node.localName == 'osm') {
|
||||
const state = pushParseAndPop({
|
||||
nodes: {},
|
||||
ways: [],
|
||||
features: []
|
||||
}, PARSERS, node, [options]);
|
||||
// parse nodes in ways
|
||||
for (let j = 0; j < state.ways.length; j++) {
|
||||
const values = /** @type {Object} */ (state.ways[j]);
|
||||
/** @type {Array.<number>} */
|
||||
const flatCoordinates = [];
|
||||
for (let i = 0, ii = values.ndrefs.length; i < ii; i++) {
|
||||
const point = state.nodes[values.ndrefs[i]];
|
||||
extend(flatCoordinates, point);
|
||||
}
|
||||
let geometry;
|
||||
if (values.ndrefs[0] == values.ndrefs[values.ndrefs.length - 1]) {
|
||||
// closed way
|
||||
geometry = new Polygon(flatCoordinates, GeometryLayout.XY, [flatCoordinates.length]);
|
||||
} else {
|
||||
geometry = new LineString(flatCoordinates, GeometryLayout.XY);
|
||||
}
|
||||
transformWithOptions(geometry, false, options);
|
||||
const feature = new Feature(geometry);
|
||||
feature.setId(values.id);
|
||||
feature.setProperties(values.tags);
|
||||
state.features.push(feature);
|
||||
}
|
||||
if (state.features) {
|
||||
return state.features;
|
||||
}
|
||||
}
|
||||
return [];
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Read the projection from an OSM source.
|
||||
*
|
||||
* @function
|
||||
* @param {Document|Node|Object|string} source Source.
|
||||
* @return {module:ol/proj/Projection} Projection.
|
||||
* @api
|
||||
*/
|
||||
OSMXML.prototype.readProjection;
|
||||
|
||||
|
||||
/**
|
||||
* Not implemented.
|
||||
* @inheritDoc
|
||||
*/
|
||||
OSMXML.prototype.writeFeatureNode = function(feature, opt_options) {};
|
||||
|
||||
|
||||
/**
|
||||
* Not implemented.
|
||||
* @inheritDoc
|
||||
*/
|
||||
OSMXML.prototype.writeFeaturesNode = function(features, opt_options) {};
|
||||
|
||||
|
||||
/**
|
||||
* Not implemented.
|
||||
* @inheritDoc
|
||||
*/
|
||||
OSMXML.prototype.writeGeometryNode = function(geometry, opt_options) {};
|
||||
export default OSMXML;
|
||||
|
||||
@@ -1,22 +1,11 @@
|
||||
/**
|
||||
* @module ol/format/OWS
|
||||
*/
|
||||
import {inherits} from '../util.js';
|
||||
import {readHref} from '../format/XLink.js';
|
||||
import XML from '../format/XML.js';
|
||||
import {readString} from '../format/xsd.js';
|
||||
import {makeObjectPropertyPusher, makeObjectPropertySetter, makeStructureNS, pushParseAndPop} from '../xml.js';
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
* @extends {module:ol/format/XML}
|
||||
*/
|
||||
const OWS = function() {
|
||||
XML.call(this);
|
||||
};
|
||||
|
||||
inherits(OWS, XML);
|
||||
|
||||
|
||||
/**
|
||||
* @const
|
||||
@@ -37,6 +26,34 @@ const PARSERS = makeStructureNS(
|
||||
});
|
||||
|
||||
|
||||
class OWS extends XML {
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
readFromDocument(doc) {
|
||||
for (let n = doc.firstChild; n; n = n.nextSibling) {
|
||||
if (n.nodeType == Node.ELEMENT_NODE) {
|
||||
return this.readFromNode(n);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
readFromNode(node) {
|
||||
const owsObject = pushParseAndPop({},
|
||||
PARSERS, node, []);
|
||||
return owsObject ? owsObject : null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @const
|
||||
* @type {Object.<string, Object.<string, module:ol/xml~Parser>>}
|
||||
@@ -187,29 +204,6 @@ const SERVICE_PROVIDER_PARSERS =
|
||||
});
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
OWS.prototype.readFromDocument = function(doc) {
|
||||
for (let n = doc.firstChild; n; n = n.nextSibling) {
|
||||
if (n.nodeType == Node.ELEMENT_NODE) {
|
||||
return this.readFromNode(n);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
OWS.prototype.readFromNode = function(node) {
|
||||
const owsObject = pushParseAndPop({},
|
||||
PARSERS, node, []);
|
||||
return owsObject ? owsObject : null;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {Node} node Node.
|
||||
* @param {Array.<*>} objectStack Object stack.
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
/**
|
||||
* @module ol/format/Polyline
|
||||
*/
|
||||
import {inherits} from '../util.js';
|
||||
import {assert} from '../asserts.js';
|
||||
import Feature from '../Feature.js';
|
||||
import {transformWithOptions} from '../format/Feature.js';
|
||||
@@ -27,37 +26,111 @@ import {get as getProjection} from '../proj.js';
|
||||
* Feature format for reading and writing data in the Encoded
|
||||
* Polyline Algorithm Format.
|
||||
*
|
||||
* @constructor
|
||||
* @extends {module:ol/format/TextFeature}
|
||||
* @param {module:ol/format/Polyline~Options=} opt_options Optional configuration object.
|
||||
* When reading features, the coordinates are assumed to be in two dimensions
|
||||
* and in [latitude, longitude] order.
|
||||
*
|
||||
* As Polyline sources contain a single feature,
|
||||
* {@link module:ol/format/Polyline~Polyline#readFeatures} will return the
|
||||
* feature in an array.
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
const Polyline = function(opt_options) {
|
||||
class Polyline extends TextFeature {
|
||||
|
||||
const options = opt_options ? opt_options : {};
|
||||
/**
|
||||
* @param {module:ol/format/Polyline~Options=} opt_options Optional configuration object.
|
||||
*/
|
||||
constructor(opt_options) {
|
||||
super();
|
||||
|
||||
TextFeature.call(this);
|
||||
const options = opt_options ? opt_options : {};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
this.dataProjection = getProjection('EPSG:4326');
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {number}
|
||||
*/
|
||||
this.factor_ = options.factor ? options.factor : 1e5;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {module:ol/geom/GeometryLayout}
|
||||
*/
|
||||
this.geometryLayout_ = options.geometryLayout ?
|
||||
options.geometryLayout : GeometryLayout.XY;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
this.dataProjection = getProjection('EPSG:4326');
|
||||
readFeatureFromText(text, opt_options) {
|
||||
const geometry = this.readGeometryFromText(text, opt_options);
|
||||
return new Feature(geometry);
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {number}
|
||||
* @inheritDoc
|
||||
*/
|
||||
this.factor_ = options.factor ? options.factor : 1e5;
|
||||
readFeaturesFromText(text, opt_options) {
|
||||
const feature = this.readFeatureFromText(text, opt_options);
|
||||
return [feature];
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {module:ol/geom/GeometryLayout}
|
||||
* @inheritDoc
|
||||
*/
|
||||
this.geometryLayout_ = options.geometryLayout ?
|
||||
options.geometryLayout : GeometryLayout.XY;
|
||||
};
|
||||
readGeometryFromText(text, opt_options) {
|
||||
const stride = getStrideForLayout(this.geometryLayout_);
|
||||
const flatCoordinates = decodeDeltas(text, stride, this.factor_);
|
||||
flipXY(flatCoordinates, 0, flatCoordinates.length, stride, flatCoordinates);
|
||||
const coordinates = inflateCoordinates(flatCoordinates, 0, flatCoordinates.length, stride);
|
||||
|
||||
inherits(Polyline, TextFeature);
|
||||
return (
|
||||
/** @type {module:ol/geom/Geometry} */ (transformWithOptions(
|
||||
new LineString(coordinates, this.geometryLayout_),
|
||||
false,
|
||||
this.adaptOptions(opt_options)
|
||||
))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
writeFeatureText(feature, opt_options) {
|
||||
const geometry = feature.getGeometry();
|
||||
if (geometry) {
|
||||
return this.writeGeometryText(geometry, opt_options);
|
||||
} else {
|
||||
assert(false, 40); // Expected `feature` to have a geometry
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
writeFeaturesText(features, opt_options) {
|
||||
return this.writeFeatureText(features[0], opt_options);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
writeGeometryText(geometry, opt_options) {
|
||||
geometry = /** @type {module:ol/geom/LineString} */
|
||||
(transformWithOptions(geometry, true, this.adaptOptions(opt_options)));
|
||||
const flatCoordinates = geometry.getFlatCoordinates();
|
||||
const stride = geometry.getStride();
|
||||
flipXY(flatCoordinates, 0, flatCoordinates.length, stride, flatCoordinates);
|
||||
return encodeDeltas(flatCoordinates, stride, this.factor_);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
@@ -264,135 +337,4 @@ export function encodeUnsignedInteger(num) {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Read the feature from the Polyline source. The coordinates are assumed to be
|
||||
* in two dimensions and in latitude, longitude order.
|
||||
*
|
||||
* @function
|
||||
* @param {Document|Node|Object|string} source Source.
|
||||
* @param {module:ol/format/Feature~ReadOptions=} opt_options Read options.
|
||||
* @return {module:ol/Feature} Feature.
|
||||
* @api
|
||||
*/
|
||||
Polyline.prototype.readFeature;
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
Polyline.prototype.readFeatureFromText = function(text, opt_options) {
|
||||
const geometry = this.readGeometryFromText(text, opt_options);
|
||||
return new Feature(geometry);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Read the feature from the source. As Polyline sources contain a single
|
||||
* feature, this will return the feature in an array.
|
||||
*
|
||||
* @function
|
||||
* @param {Document|Node|Object|string} source Source.
|
||||
* @param {module:ol/format/Feature~ReadOptions=} opt_options Read options.
|
||||
* @return {Array.<module:ol/Feature>} Features.
|
||||
* @api
|
||||
*/
|
||||
Polyline.prototype.readFeatures;
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
Polyline.prototype.readFeaturesFromText = function(text, opt_options) {
|
||||
const feature = this.readFeatureFromText(text, opt_options);
|
||||
return [feature];
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Read the geometry from the source.
|
||||
*
|
||||
* @function
|
||||
* @param {Document|Node|Object|string} source Source.
|
||||
* @param {module:ol/format/Feature~ReadOptions=} opt_options Read options.
|
||||
* @return {module:ol/geom/Geometry} Geometry.
|
||||
* @api
|
||||
*/
|
||||
Polyline.prototype.readGeometry;
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
Polyline.prototype.readGeometryFromText = function(text, opt_options) {
|
||||
const stride = getStrideForLayout(this.geometryLayout_);
|
||||
const flatCoordinates = decodeDeltas(text, stride, this.factor_);
|
||||
flipXY(flatCoordinates, 0, flatCoordinates.length, stride, flatCoordinates);
|
||||
const coordinates = inflateCoordinates(flatCoordinates, 0, flatCoordinates.length, stride);
|
||||
|
||||
return (
|
||||
/** @type {module:ol/geom/Geometry} */ (transformWithOptions(
|
||||
new LineString(coordinates, this.geometryLayout_),
|
||||
false,
|
||||
this.adaptOptions(opt_options)
|
||||
))
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Read the projection from a Polyline source.
|
||||
*
|
||||
* @function
|
||||
* @param {Document|Node|Object|string} source Source.
|
||||
* @return {module:ol/proj/Projection} Projection.
|
||||
* @api
|
||||
*/
|
||||
Polyline.prototype.readProjection;
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
Polyline.prototype.writeFeatureText = function(feature, opt_options) {
|
||||
const geometry = feature.getGeometry();
|
||||
if (geometry) {
|
||||
return this.writeGeometryText(geometry, opt_options);
|
||||
} else {
|
||||
assert(false, 40); // Expected `feature` to have a geometry
|
||||
return '';
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
Polyline.prototype.writeFeaturesText = function(features, opt_options) {
|
||||
return this.writeFeatureText(features[0], opt_options);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Write a single geometry in Polyline format.
|
||||
*
|
||||
* @function
|
||||
* @param {module:ol/geom/Geometry} geometry Geometry.
|
||||
* @param {module:ol/format/Feature~WriteOptions=} opt_options Write options.
|
||||
* @return {string} Geometry.
|
||||
* @api
|
||||
*/
|
||||
Polyline.prototype.writeGeometry;
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
Polyline.prototype.writeGeometryText = function(geometry, opt_options) {
|
||||
geometry = /** @type {module:ol/geom/LineString} */
|
||||
(transformWithOptions(geometry, true, this.adaptOptions(opt_options)));
|
||||
const flatCoordinates = geometry.getFlatCoordinates();
|
||||
const stride = geometry.getStride();
|
||||
flipXY(flatCoordinates, 0, flatCoordinates.length, stride, flatCoordinates);
|
||||
return encodeDeltas(flatCoordinates, stride, this.factor_);
|
||||
};
|
||||
export default Polyline;
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
/**
|
||||
* @module ol/format/TextFeature
|
||||
*/
|
||||
import {inherits} from '../util.js';
|
||||
import FeatureFormat from '../format/Feature.js';
|
||||
import FormatType from '../format/FormatType.js';
|
||||
|
||||
@@ -11,15 +10,169 @@ import FormatType from '../format/FormatType.js';
|
||||
* instantiated in apps.
|
||||
* Base class for text feature formats.
|
||||
*
|
||||
* @constructor
|
||||
* @abstract
|
||||
* @extends {module:ol/format/Feature}
|
||||
*/
|
||||
const TextFeature = function() {
|
||||
FeatureFormat.call(this);
|
||||
};
|
||||
class TextFeature extends FeatureFormat {
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
|
||||
inherits(TextFeature, FeatureFormat);
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
getType() {
|
||||
return FormatType.TEXT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the feature from the source.
|
||||
*
|
||||
* @param {Document|Node|Object|string} source Source.
|
||||
* @param {module:ol/format/Feature~ReadOptions=} opt_options Read options.
|
||||
* @return {module:ol/Feature} Feature.
|
||||
* @api
|
||||
*/
|
||||
readFeature(source, opt_options) {
|
||||
return this.readFeatureFromText(getText(source), this.adaptOptions(opt_options));
|
||||
}
|
||||
|
||||
/**
|
||||
* @abstract
|
||||
* @param {string} text Text.
|
||||
* @param {module:ol/format/Feature~ReadOptions=} opt_options Read options.
|
||||
* @protected
|
||||
* @return {module:ol/Feature} Feature.
|
||||
*/
|
||||
readFeatureFromText(text, opt_options) {}
|
||||
|
||||
/**
|
||||
* Read the features from the source.
|
||||
*
|
||||
* @param {Document|Node|Object|string} source Source.
|
||||
* @param {module:ol/format/Feature~ReadOptions=} opt_options Read options.
|
||||
* @return {Array.<module:ol/Feature>} Features.
|
||||
* @api
|
||||
*/
|
||||
readFeatures(source, opt_options) {
|
||||
return this.readFeaturesFromText(getText(source), this.adaptOptions(opt_options));
|
||||
}
|
||||
|
||||
/**
|
||||
* @abstract
|
||||
* @param {string} text Text.
|
||||
* @param {module:ol/format/Feature~ReadOptions=} opt_options Read options.
|
||||
* @protected
|
||||
* @return {Array.<module:ol/Feature>} Features.
|
||||
*/
|
||||
readFeaturesFromText(text, opt_options) {}
|
||||
|
||||
/**
|
||||
* Read the geometry from the source.
|
||||
*
|
||||
* @param {Document|Node|Object|string} source Source.
|
||||
* @param {module:ol/format/Feature~ReadOptions=} opt_options Read options.
|
||||
* @return {module:ol/geom/Geometry} Geometry.
|
||||
* @api
|
||||
*/
|
||||
readGeometry(source, opt_options) {
|
||||
return this.readGeometryFromText(getText(source), this.adaptOptions(opt_options));
|
||||
}
|
||||
|
||||
/**
|
||||
* @abstract
|
||||
* @param {string} text Text.
|
||||
* @param {module:ol/format/Feature~ReadOptions=} opt_options Read options.
|
||||
* @protected
|
||||
* @return {module:ol/geom/Geometry} Geometry.
|
||||
*/
|
||||
readGeometryFromText(text, opt_options) {}
|
||||
|
||||
/**
|
||||
* Read the projection from the source.
|
||||
*
|
||||
* @function
|
||||
* @param {Document|Node|Object|string} source Source.
|
||||
* @return {module:ol/proj/Projection} Projection.
|
||||
* @api
|
||||
*/
|
||||
readProjection(source) {
|
||||
return this.readProjectionFromText(getText(source));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} text Text.
|
||||
* @protected
|
||||
* @return {module:ol/proj/Projection} Projection.
|
||||
*/
|
||||
readProjectionFromText(text) {
|
||||
return this.dataProjection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode a feature as a string.
|
||||
*
|
||||
* @function
|
||||
* @param {module:ol/Feature} feature Feature.
|
||||
* @param {module:ol/format/Feature~WriteOptions=} opt_options Write options.
|
||||
* @return {string} Encoded feature.
|
||||
* @api
|
||||
*/
|
||||
writeFeature(feature, opt_options) {
|
||||
return this.writeFeatureText(feature, this.adaptOptions(opt_options));
|
||||
}
|
||||
|
||||
/**
|
||||
* @abstract
|
||||
* @param {module:ol/Feature} feature Features.
|
||||
* @param {module:ol/format/Feature~WriteOptions=} opt_options Write options.
|
||||
* @protected
|
||||
* @return {string} Text.
|
||||
*/
|
||||
writeFeatureText(feature, opt_options) {}
|
||||
|
||||
/**
|
||||
* Encode an array of features as string.
|
||||
*
|
||||
* @param {Array.<module:ol/Feature>} features Features.
|
||||
* @param {module:ol/format/Feature~WriteOptions=} opt_options Write options.
|
||||
* @return {string} Encoded features.
|
||||
* @api
|
||||
*/
|
||||
writeFeatures(features, opt_options) {
|
||||
return this.writeFeaturesText(features, this.adaptOptions(opt_options));
|
||||
}
|
||||
|
||||
/**
|
||||
* @abstract
|
||||
* @param {Array.<module:ol/Feature>} features Features.
|
||||
* @param {module:ol/format/Feature~WriteOptions=} opt_options Write options.
|
||||
* @protected
|
||||
* @return {string} Text.
|
||||
*/
|
||||
writeFeaturesText(features, opt_options) {}
|
||||
|
||||
/**
|
||||
* Write a single geometry.
|
||||
*
|
||||
* @function
|
||||
* @param {module:ol/geom/Geometry} geometry Geometry.
|
||||
* @param {module:ol/format/Feature~WriteOptions=} opt_options Write options.
|
||||
* @return {string} Geometry.
|
||||
* @api
|
||||
*/
|
||||
writeGeometry(geometry, opt_options) {
|
||||
return this.writeGeometryText(geometry, this.adaptOptions(opt_options));
|
||||
}
|
||||
|
||||
/**
|
||||
* @abstract
|
||||
* @param {module:ol/geom/Geometry} geometry Geometry.
|
||||
* @param {module:ol/format/Feature~WriteOptions=} opt_options Write options.
|
||||
* @protected
|
||||
* @return {string} Text.
|
||||
*/
|
||||
writeGeometryText(geometry, opt_options) {}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
@@ -35,136 +188,4 @@ function getText(source) {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
TextFeature.prototype.getType = function() {
|
||||
return FormatType.TEXT;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
TextFeature.prototype.readFeature = function(source, opt_options) {
|
||||
return this.readFeatureFromText(getText(source), this.adaptOptions(opt_options));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @abstract
|
||||
* @param {string} text Text.
|
||||
* @param {module:ol/format/Feature~ReadOptions=} opt_options Read options.
|
||||
* @protected
|
||||
* @return {module:ol/Feature} Feature.
|
||||
*/
|
||||
TextFeature.prototype.readFeatureFromText = function(text, opt_options) {};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
TextFeature.prototype.readFeatures = function(source, opt_options) {
|
||||
return this.readFeaturesFromText(getText(source), this.adaptOptions(opt_options));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @abstract
|
||||
* @param {string} text Text.
|
||||
* @param {module:ol/format/Feature~ReadOptions=} opt_options Read options.
|
||||
* @protected
|
||||
* @return {Array.<module:ol/Feature>} Features.
|
||||
*/
|
||||
TextFeature.prototype.readFeaturesFromText = function(text, opt_options) {};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
TextFeature.prototype.readGeometry = function(source, opt_options) {
|
||||
return this.readGeometryFromText(getText(source), this.adaptOptions(opt_options));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @abstract
|
||||
* @param {string} text Text.
|
||||
* @param {module:ol/format/Feature~ReadOptions=} opt_options Read options.
|
||||
* @protected
|
||||
* @return {module:ol/geom/Geometry} Geometry.
|
||||
*/
|
||||
TextFeature.prototype.readGeometryFromText = function(text, opt_options) {};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
TextFeature.prototype.readProjection = function(source) {
|
||||
return this.readProjectionFromText(getText(source));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {string} text Text.
|
||||
* @protected
|
||||
* @return {module:ol/proj/Projection} Projection.
|
||||
*/
|
||||
TextFeature.prototype.readProjectionFromText = function(text) {
|
||||
return this.dataProjection;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
TextFeature.prototype.writeFeature = function(feature, opt_options) {
|
||||
return this.writeFeatureText(feature, this.adaptOptions(opt_options));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @abstract
|
||||
* @param {module:ol/Feature} feature Features.
|
||||
* @param {module:ol/format/Feature~WriteOptions=} opt_options Write options.
|
||||
* @protected
|
||||
* @return {string} Text.
|
||||
*/
|
||||
TextFeature.prototype.writeFeatureText = function(feature, opt_options) {};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
TextFeature.prototype.writeFeatures = function(features, opt_options) {
|
||||
return this.writeFeaturesText(features, this.adaptOptions(opt_options));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @abstract
|
||||
* @param {Array.<module:ol/Feature>} features Features.
|
||||
* @param {module:ol/format/Feature~WriteOptions=} opt_options Write options.
|
||||
* @protected
|
||||
* @return {string} Text.
|
||||
*/
|
||||
TextFeature.prototype.writeFeaturesText = function(features, opt_options) {};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
TextFeature.prototype.writeGeometry = function(geometry, opt_options) {
|
||||
return this.writeGeometryText(geometry, this.adaptOptions(opt_options));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @abstract
|
||||
* @param {module:ol/geom/Geometry} geometry Geometry.
|
||||
* @param {module:ol/format/Feature~WriteOptions=} opt_options Write options.
|
||||
* @protected
|
||||
* @return {string} Text.
|
||||
*/
|
||||
TextFeature.prototype.writeGeometryText = function(geometry, opt_options) {};
|
||||
export default TextFeature;
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
/**
|
||||
* @module ol/format/TopoJSON
|
||||
*/
|
||||
import {inherits} from '../util.js';
|
||||
import Feature from '../Feature.js';
|
||||
import {transformWithOptions} from '../format/Feature.js';
|
||||
import JSONFeature from '../format/JSONFeature.js';
|
||||
@@ -43,39 +42,117 @@ import {get as getProjection} from '../proj.js';
|
||||
* @classdesc
|
||||
* Feature format for reading data in the TopoJSON format.
|
||||
*
|
||||
* @constructor
|
||||
* @extends {module:ol/format/JSONFeature}
|
||||
* @param {module:ol/format/TopoJSON~Options=} opt_options Options.
|
||||
* @api
|
||||
*/
|
||||
const TopoJSON = function(opt_options) {
|
||||
|
||||
const options = opt_options ? opt_options : {};
|
||||
|
||||
JSONFeature.call(this);
|
||||
class TopoJSON extends JSONFeature {
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {string|undefined}
|
||||
* @param {module:ol/format/TopoJSON~Options=} opt_options Options.
|
||||
*/
|
||||
this.layerName_ = options.layerName;
|
||||
constructor(opt_options) {
|
||||
super();
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {Array.<string>}
|
||||
*/
|
||||
this.layers_ = options.layers ? options.layers : null;
|
||||
const options = opt_options ? opt_options : {};
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {string|undefined}
|
||||
*/
|
||||
this.layerName_ = options.layerName;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {Array.<string>}
|
||||
*/
|
||||
this.layers_ = options.layers ? options.layers : null;
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
this.dataProjection = getProjection(
|
||||
options.dataProjection ?
|
||||
options.dataProjection : 'EPSG:4326');
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
this.dataProjection = getProjection(
|
||||
options.dataProjection ?
|
||||
options.dataProjection : 'EPSG:4326');
|
||||
readFeaturesFromObject(object, opt_options) {
|
||||
if (object.type == 'Topology') {
|
||||
const topoJSONTopology = /** @type {TopoJSONTopology} */ (object);
|
||||
let transform, scale = null, translate = null;
|
||||
if (topoJSONTopology.transform) {
|
||||
transform = topoJSONTopology.transform;
|
||||
scale = transform.scale;
|
||||
translate = transform.translate;
|
||||
}
|
||||
const arcs = topoJSONTopology.arcs;
|
||||
if (transform) {
|
||||
transformArcs(arcs, scale, translate);
|
||||
}
|
||||
/** @type {Array.<module:ol/Feature>} */
|
||||
const features = [];
|
||||
const topoJSONFeatures = topoJSONTopology.objects;
|
||||
const property = this.layerName_;
|
||||
let feature;
|
||||
for (const objectName in topoJSONFeatures) {
|
||||
if (this.layers_ && this.layers_.indexOf(objectName) == -1) {
|
||||
continue;
|
||||
}
|
||||
if (topoJSONFeatures[objectName].type === 'GeometryCollection') {
|
||||
feature = /** @type {TopoJSONGeometryCollection} */ (topoJSONFeatures[objectName]);
|
||||
features.push.apply(features, readFeaturesFromGeometryCollection(
|
||||
feature, arcs, scale, translate, property, objectName, opt_options));
|
||||
} else {
|
||||
feature = /** @type {TopoJSONGeometry} */ (topoJSONFeatures[objectName]);
|
||||
features.push(readFeatureFromGeometry(
|
||||
feature, arcs, scale, translate, property, objectName, opt_options));
|
||||
}
|
||||
}
|
||||
return features;
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
readProjectionFromObject(object) {
|
||||
return this.dataProjection;
|
||||
}
|
||||
|
||||
inherits(TopoJSON, JSONFeature);
|
||||
/**
|
||||
* Not implemented.
|
||||
* @inheritDoc
|
||||
*/
|
||||
writeFeatureObject(feature, opt_options) {}
|
||||
|
||||
/**
|
||||
* Not implemented.
|
||||
* @inheritDoc
|
||||
*/
|
||||
writeFeaturesObject(features, opt_options) {}
|
||||
|
||||
/**
|
||||
* Not implemented.
|
||||
* @inheritDoc
|
||||
*/
|
||||
writeGeometryObject(geometry, opt_options) {}
|
||||
|
||||
/**
|
||||
* Not implemented.
|
||||
* @override
|
||||
*/
|
||||
readGeometryFromObject() {}
|
||||
|
||||
/**
|
||||
* Not implemented.
|
||||
* @override
|
||||
*/
|
||||
readFeatureFromObject() {}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
@@ -298,59 +375,6 @@ function readFeatureFromGeometry(object, arcs, scale, translate, property, name,
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Read all features from a TopoJSON source.
|
||||
*
|
||||
* @function
|
||||
* @param {Document|Node|Object|string} source Source.
|
||||
* @return {Array.<module:ol/Feature>} Features.
|
||||
* @api
|
||||
*/
|
||||
TopoJSON.prototype.readFeatures;
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
TopoJSON.prototype.readFeaturesFromObject = function(object, opt_options) {
|
||||
if (object.type == 'Topology') {
|
||||
const topoJSONTopology = /** @type {TopoJSONTopology} */ (object);
|
||||
let transform, scale = null, translate = null;
|
||||
if (topoJSONTopology.transform) {
|
||||
transform = topoJSONTopology.transform;
|
||||
scale = transform.scale;
|
||||
translate = transform.translate;
|
||||
}
|
||||
const arcs = topoJSONTopology.arcs;
|
||||
if (transform) {
|
||||
transformArcs(arcs, scale, translate);
|
||||
}
|
||||
/** @type {Array.<module:ol/Feature>} */
|
||||
const features = [];
|
||||
const topoJSONFeatures = topoJSONTopology.objects;
|
||||
const property = this.layerName_;
|
||||
let feature;
|
||||
for (const objectName in topoJSONFeatures) {
|
||||
if (this.layers_ && this.layers_.indexOf(objectName) == -1) {
|
||||
continue;
|
||||
}
|
||||
if (topoJSONFeatures[objectName].type === 'GeometryCollection') {
|
||||
feature = /** @type {TopoJSONGeometryCollection} */ (topoJSONFeatures[objectName]);
|
||||
features.push.apply(features, readFeaturesFromGeometryCollection(
|
||||
feature, arcs, scale, translate, property, objectName, opt_options));
|
||||
} else {
|
||||
feature = /** @type {TopoJSONGeometry} */ (topoJSONFeatures[objectName]);
|
||||
features.push(readFeatureFromGeometry(
|
||||
feature, arcs, scale, translate, property, objectName, opt_options));
|
||||
}
|
||||
}
|
||||
return features;
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Apply a linear transform to array of arcs. The provided array of arcs is
|
||||
* modified in place.
|
||||
@@ -401,56 +425,4 @@ function transformVertex(vertex, scale, translate) {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Read the projection from a TopoJSON source.
|
||||
*
|
||||
* @param {Document|Node|Object|string} object Source.
|
||||
* @return {module:ol/proj/Projection} Projection.
|
||||
* @override
|
||||
* @api
|
||||
*/
|
||||
TopoJSON.prototype.readProjection;
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
TopoJSON.prototype.readProjectionFromObject = function(object) {
|
||||
return this.dataProjection;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Not implemented.
|
||||
* @inheritDoc
|
||||
*/
|
||||
TopoJSON.prototype.writeFeatureObject = function(feature, opt_options) {};
|
||||
|
||||
|
||||
/**
|
||||
* Not implemented.
|
||||
* @inheritDoc
|
||||
*/
|
||||
TopoJSON.prototype.writeFeaturesObject = function(features, opt_options) {};
|
||||
|
||||
|
||||
/**
|
||||
* Not implemented.
|
||||
* @inheritDoc
|
||||
*/
|
||||
TopoJSON.prototype.writeGeometryObject = function(geometry, opt_options) {};
|
||||
|
||||
|
||||
/**
|
||||
* Not implemented.
|
||||
* @override
|
||||
*/
|
||||
TopoJSON.prototype.readGeometryFromObject = function() {};
|
||||
|
||||
|
||||
/**
|
||||
* Not implemented.
|
||||
* @override
|
||||
*/
|
||||
TopoJSON.prototype.readFeatureFromObject = function() {};
|
||||
export default TopoJSON;
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
/**
|
||||
* @module ol/format/WFS
|
||||
*/
|
||||
import {inherits} from '../util.js';
|
||||
import {assert} from '../asserts.js';
|
||||
import GML2 from '../format/GML2.js';
|
||||
import GML3 from '../format/GML3.js';
|
||||
@@ -17,6 +16,69 @@ import {createElementNS, isDocument, isNode, makeArrayPusher, makeChildAppender,
|
||||
pushParseAndPop, pushSerializeAndPop, XML_SCHEMA_INSTANCE_URI} from '../xml.js';
|
||||
|
||||
|
||||
/**
|
||||
* @const
|
||||
* @type {Object.<string, Object.<string, module:ol/xml~Parser>>}
|
||||
*/
|
||||
const FEATURE_COLLECTION_PARSERS = {
|
||||
'http://www.opengis.net/gml': {
|
||||
'boundedBy': makeObjectPropertySetter(
|
||||
GMLBase.prototype.readGeometryElement, 'bounds')
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @const
|
||||
* @type {Object.<string, Object.<string, module:ol/xml~Parser>>}
|
||||
*/
|
||||
const TRANSACTION_SUMMARY_PARSERS = {
|
||||
'http://www.opengis.net/wfs': {
|
||||
'totalInserted': makeObjectPropertySetter(readNonNegativeInteger),
|
||||
'totalUpdated': makeObjectPropertySetter(readNonNegativeInteger),
|
||||
'totalDeleted': makeObjectPropertySetter(readNonNegativeInteger)
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @const
|
||||
* @type {Object.<string, Object.<string, module:ol/xml~Parser>>}
|
||||
*/
|
||||
const TRANSACTION_RESPONSE_PARSERS = {
|
||||
'http://www.opengis.net/wfs': {
|
||||
'TransactionSummary': makeObjectPropertySetter(
|
||||
readTransactionSummary, 'transactionSummary'),
|
||||
'InsertResults': makeObjectPropertySetter(
|
||||
readInsertResults, 'insertIds')
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @type {Object.<string, Object.<string, module:ol/xml~Serializer>>}
|
||||
*/
|
||||
const QUERY_SERIALIZERS = {
|
||||
'http://www.opengis.net/wfs': {
|
||||
'PropertyName': makeChildAppender(writeStringTextNode)
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @type {Object.<string, Object.<string, module:ol/xml~Serializer>>}
|
||||
*/
|
||||
const TRANSACTION_SERIALIZERS = {
|
||||
'http://www.opengis.net/wfs': {
|
||||
'Insert': makeChildAppender(writeFeature),
|
||||
'Update': makeChildAppender(writeUpdate),
|
||||
'Delete': makeChildAppender(writeDelete),
|
||||
'Property': makeChildAppender(writeProperty),
|
||||
'Native': makeChildAppender(writeNative)
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @typedef {Object} Options
|
||||
* @property {Object.<string, string>|string} [featureNS] The namespace URI used for features.
|
||||
@@ -138,197 +200,340 @@ const DEFAULT_VERSION = '1.1.0';
|
||||
* as option if you want to read a WFS that contains GML2 (WFS 1.0.0).
|
||||
* Also see {@link module:ol/format/GMLBase~GMLBase} which is used by this format.
|
||||
*
|
||||
* @constructor
|
||||
* @param {module:ol/format/WFS~Options=} opt_options Optional configuration object.
|
||||
* @extends {module:ol/format/XMLFeature}
|
||||
* @api
|
||||
*/
|
||||
const WFS = function(opt_options) {
|
||||
const options = opt_options ? opt_options : {};
|
||||
class WFS extends XMLFeature {
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {Array.<string>|string|undefined}
|
||||
* @param {module:ol/format/WFS~Options=} opt_options Optional configuration object.
|
||||
*/
|
||||
this.featureType_ = options.featureType;
|
||||
constructor(opt_options) {
|
||||
super();
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {Object.<string, string>|string|undefined}
|
||||
*/
|
||||
this.featureNS_ = options.featureNS;
|
||||
const options = opt_options ? opt_options : {};
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {module:ol/format/GMLBase}
|
||||
*/
|
||||
this.gmlFormat_ = options.gmlFormat ?
|
||||
options.gmlFormat : new GML3();
|
||||
/**
|
||||
* @private
|
||||
* @type {Array.<string>|string|undefined}
|
||||
*/
|
||||
this.featureType_ = options.featureType;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {string}
|
||||
*/
|
||||
this.schemaLocation_ = options.schemaLocation ?
|
||||
options.schemaLocation : SCHEMA_LOCATIONS[DEFAULT_VERSION];
|
||||
/**
|
||||
* @private
|
||||
* @type {Object.<string, string>|string|undefined}
|
||||
*/
|
||||
this.featureNS_ = options.featureNS;
|
||||
|
||||
XMLFeature.call(this);
|
||||
};
|
||||
/**
|
||||
* @private
|
||||
* @type {module:ol/format/GMLBase}
|
||||
*/
|
||||
this.gmlFormat_ = options.gmlFormat ?
|
||||
options.gmlFormat : new GML3();
|
||||
|
||||
inherits(WFS, XMLFeature);
|
||||
|
||||
|
||||
/**
|
||||
* @return {Array.<string>|string|undefined} featureType
|
||||
*/
|
||||
WFS.prototype.getFeatureType = function() {
|
||||
return this.featureType_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {Array.<string>|string|undefined} featureType Feature type(s) to parse.
|
||||
*/
|
||||
WFS.prototype.setFeatureType = function(featureType) {
|
||||
this.featureType_ = featureType;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Read all features from a WFS FeatureCollection.
|
||||
*
|
||||
* @function
|
||||
* @param {Document|Node|Object|string} source Source.
|
||||
* @param {module:ol/format/Feature~ReadOptions=} opt_options Read options.
|
||||
* @return {Array.<module:ol/Feature>} Features.
|
||||
* @api
|
||||
*/
|
||||
WFS.prototype.readFeatures;
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
WFS.prototype.readFeaturesFromNode = function(node, opt_options) {
|
||||
const context = /** @type {module:ol/xml~NodeStackItem} */ ({
|
||||
'featureType': this.featureType_,
|
||||
'featureNS': this.featureNS_
|
||||
});
|
||||
assign(context, this.getReadOptions(node, opt_options ? opt_options : {}));
|
||||
const objectStack = [context];
|
||||
this.gmlFormat_.FEATURE_COLLECTION_PARSERS[GMLNS][
|
||||
'featureMember'] =
|
||||
makeArrayPusher(GMLBase.prototype.readFeaturesInternal);
|
||||
let features = pushParseAndPop([],
|
||||
this.gmlFormat_.FEATURE_COLLECTION_PARSERS, node,
|
||||
objectStack, this.gmlFormat_);
|
||||
if (!features) {
|
||||
features = [];
|
||||
/**
|
||||
* @private
|
||||
* @type {string}
|
||||
*/
|
||||
this.schemaLocation_ = options.schemaLocation ?
|
||||
options.schemaLocation : SCHEMA_LOCATIONS[DEFAULT_VERSION];
|
||||
}
|
||||
return features;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Read transaction response of the source.
|
||||
*
|
||||
* @param {Document|Node|Object|string} source Source.
|
||||
* @return {module:ol/format/WFS~TransactionResponse|undefined} Transaction response.
|
||||
* @api
|
||||
*/
|
||||
WFS.prototype.readTransactionResponse = function(source) {
|
||||
if (isDocument(source)) {
|
||||
return this.readTransactionResponseFromDocument(
|
||||
/** @type {Document} */ (source));
|
||||
} else if (isNode(source)) {
|
||||
return this.readTransactionResponseFromNode(/** @type {Node} */ (source));
|
||||
} else if (typeof source === 'string') {
|
||||
const doc = parse(source);
|
||||
return this.readTransactionResponseFromDocument(doc);
|
||||
} else {
|
||||
return undefined;
|
||||
/**
|
||||
* @return {Array.<string>|string|undefined} featureType
|
||||
*/
|
||||
getFeatureType() {
|
||||
return this.featureType_;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Read feature collection metadata of the source.
|
||||
*
|
||||
* @param {Document|Node|Object|string} source Source.
|
||||
* @return {module:ol/format/WFS~FeatureCollectionMetadata|undefined}
|
||||
* FeatureCollection metadata.
|
||||
* @api
|
||||
*/
|
||||
WFS.prototype.readFeatureCollectionMetadata = function(source) {
|
||||
if (isDocument(source)) {
|
||||
return this.readFeatureCollectionMetadataFromDocument(
|
||||
/** @type {Document} */ (source));
|
||||
} else if (isNode(source)) {
|
||||
return this.readFeatureCollectionMetadataFromNode(
|
||||
/** @type {Node} */ (source));
|
||||
} else if (typeof source === 'string') {
|
||||
const doc = parse(source);
|
||||
return this.readFeatureCollectionMetadataFromDocument(doc);
|
||||
} else {
|
||||
return undefined;
|
||||
/**
|
||||
* @param {Array.<string>|string|undefined} featureType Feature type(s) to parse.
|
||||
*/
|
||||
setFeatureType(featureType) {
|
||||
this.featureType_ = featureType;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
readFeaturesFromNode(node, opt_options) {
|
||||
const context = /** @type {module:ol/xml~NodeStackItem} */ ({
|
||||
'featureType': this.featureType_,
|
||||
'featureNS': this.featureNS_
|
||||
});
|
||||
assign(context, this.getReadOptions(node, opt_options ? opt_options : {}));
|
||||
const objectStack = [context];
|
||||
this.gmlFormat_.FEATURE_COLLECTION_PARSERS[GMLNS][
|
||||
'featureMember'] =
|
||||
makeArrayPusher(GMLBase.prototype.readFeaturesInternal);
|
||||
let features = pushParseAndPop([],
|
||||
this.gmlFormat_.FEATURE_COLLECTION_PARSERS, node,
|
||||
objectStack, this.gmlFormat_);
|
||||
if (!features) {
|
||||
features = [];
|
||||
}
|
||||
return features;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Document} doc Document.
|
||||
* @return {module:ol/format/WFS~FeatureCollectionMetadata|undefined}
|
||||
* FeatureCollection metadata.
|
||||
*/
|
||||
WFS.prototype.readFeatureCollectionMetadataFromDocument = function(doc) {
|
||||
for (let n = doc.firstChild; n; n = n.nextSibling) {
|
||||
if (n.nodeType == Node.ELEMENT_NODE) {
|
||||
return this.readFeatureCollectionMetadataFromNode(n);
|
||||
/**
|
||||
* Read transaction response of the source.
|
||||
*
|
||||
* @param {Document|Node|Object|string} source Source.
|
||||
* @return {module:ol/format/WFS~TransactionResponse|undefined} Transaction response.
|
||||
* @api
|
||||
*/
|
||||
readTransactionResponse(source) {
|
||||
if (isDocument(source)) {
|
||||
return this.readTransactionResponseFromDocument(
|
||||
/** @type {Document} */ (source));
|
||||
} else if (isNode(source)) {
|
||||
return this.readTransactionResponseFromNode(/** @type {Node} */ (source));
|
||||
} else if (typeof source === 'string') {
|
||||
const doc = parse(source);
|
||||
return this.readTransactionResponseFromDocument(doc);
|
||||
} else {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @const
|
||||
* @type {Object.<string, Object.<string, module:ol/xml~Parser>>}
|
||||
*/
|
||||
const FEATURE_COLLECTION_PARSERS = {
|
||||
'http://www.opengis.net/gml': {
|
||||
'boundedBy': makeObjectPropertySetter(
|
||||
GMLBase.prototype.readGeometryElement, 'bounds')
|
||||
/**
|
||||
* Read feature collection metadata of the source.
|
||||
*
|
||||
* @param {Document|Node|Object|string} source Source.
|
||||
* @return {module:ol/format/WFS~FeatureCollectionMetadata|undefined}
|
||||
* FeatureCollection metadata.
|
||||
* @api
|
||||
*/
|
||||
readFeatureCollectionMetadata(source) {
|
||||
if (isDocument(source)) {
|
||||
return this.readFeatureCollectionMetadataFromDocument(
|
||||
/** @type {Document} */ (source));
|
||||
} else if (isNode(source)) {
|
||||
return this.readFeatureCollectionMetadataFromNode(
|
||||
/** @type {Node} */ (source));
|
||||
} else if (typeof source === 'string') {
|
||||
const doc = parse(source);
|
||||
return this.readFeatureCollectionMetadataFromDocument(doc);
|
||||
} else {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {Node} node Node.
|
||||
* @return {module:ol/format/WFS~FeatureCollectionMetadata|undefined}
|
||||
* FeatureCollection metadata.
|
||||
*/
|
||||
WFS.prototype.readFeatureCollectionMetadataFromNode = function(node) {
|
||||
const result = {};
|
||||
const value = readNonNegativeIntegerString(
|
||||
node.getAttribute('numberOfFeatures'));
|
||||
result['numberOfFeatures'] = value;
|
||||
return pushParseAndPop(
|
||||
/** @type {module:ol/format/WFS~FeatureCollectionMetadata} */ (result),
|
||||
FEATURE_COLLECTION_PARSERS, node, [], this.gmlFormat_);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @const
|
||||
* @type {Object.<string, Object.<string, module:ol/xml~Parser>>}
|
||||
*/
|
||||
const TRANSACTION_SUMMARY_PARSERS = {
|
||||
'http://www.opengis.net/wfs': {
|
||||
'totalInserted': makeObjectPropertySetter(readNonNegativeInteger),
|
||||
'totalUpdated': makeObjectPropertySetter(readNonNegativeInteger),
|
||||
'totalDeleted': makeObjectPropertySetter(readNonNegativeInteger)
|
||||
/**
|
||||
* @param {Document} doc Document.
|
||||
* @return {module:ol/format/WFS~FeatureCollectionMetadata|undefined}
|
||||
* FeatureCollection metadata.
|
||||
*/
|
||||
readFeatureCollectionMetadataFromDocument(doc) {
|
||||
for (let n = doc.firstChild; n; n = n.nextSibling) {
|
||||
if (n.nodeType == Node.ELEMENT_NODE) {
|
||||
return this.readFeatureCollectionMetadataFromNode(n);
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {Node} node Node.
|
||||
* @return {module:ol/format/WFS~FeatureCollectionMetadata|undefined}
|
||||
* FeatureCollection metadata.
|
||||
*/
|
||||
readFeatureCollectionMetadataFromNode(node) {
|
||||
const result = {};
|
||||
const value = readNonNegativeIntegerString(
|
||||
node.getAttribute('numberOfFeatures'));
|
||||
result['numberOfFeatures'] = value;
|
||||
return pushParseAndPop(
|
||||
/** @type {module:ol/format/WFS~FeatureCollectionMetadata} */ (result),
|
||||
FEATURE_COLLECTION_PARSERS, node, [], this.gmlFormat_);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Document} doc Document.
|
||||
* @return {module:ol/format/WFS~TransactionResponse|undefined} Transaction response.
|
||||
*/
|
||||
readTransactionResponseFromDocument(doc) {
|
||||
for (let n = doc.firstChild; n; n = n.nextSibling) {
|
||||
if (n.nodeType == Node.ELEMENT_NODE) {
|
||||
return this.readTransactionResponseFromNode(n);
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Node} node Node.
|
||||
* @return {module:ol/format/WFS~TransactionResponse|undefined} Transaction response.
|
||||
*/
|
||||
readTransactionResponseFromNode(node) {
|
||||
return pushParseAndPop(
|
||||
/** @type {module:ol/format/WFS~TransactionResponse} */({}),
|
||||
TRANSACTION_RESPONSE_PARSERS, node, []);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode format as WFS `GetFeature` and return the Node.
|
||||
*
|
||||
* @param {module:ol/format/WFS~WriteGetFeatureOptions} options Options.
|
||||
* @return {Node} Result.
|
||||
* @api
|
||||
*/
|
||||
writeGetFeature(options) {
|
||||
const node = createElementNS(WFSNS, 'GetFeature');
|
||||
node.setAttribute('service', 'WFS');
|
||||
node.setAttribute('version', '1.1.0');
|
||||
let filter;
|
||||
if (options) {
|
||||
if (options.handle) {
|
||||
node.setAttribute('handle', options.handle);
|
||||
}
|
||||
if (options.outputFormat) {
|
||||
node.setAttribute('outputFormat', options.outputFormat);
|
||||
}
|
||||
if (options.maxFeatures !== undefined) {
|
||||
node.setAttribute('maxFeatures', options.maxFeatures);
|
||||
}
|
||||
if (options.resultType) {
|
||||
node.setAttribute('resultType', options.resultType);
|
||||
}
|
||||
if (options.startIndex !== undefined) {
|
||||
node.setAttribute('startIndex', options.startIndex);
|
||||
}
|
||||
if (options.count !== undefined) {
|
||||
node.setAttribute('count', options.count);
|
||||
}
|
||||
filter = options.filter;
|
||||
if (options.bbox) {
|
||||
assert(options.geometryName,
|
||||
12); // `options.geometryName` must also be provided when `options.bbox` is set
|
||||
const bbox = bboxFilter(
|
||||
/** @type {string} */ (options.geometryName), options.bbox, options.srsName);
|
||||
if (filter) {
|
||||
// if bbox and filter are both set, combine the two into a single filter
|
||||
filter = andFilter(filter, bbox);
|
||||
} else {
|
||||
filter = bbox;
|
||||
}
|
||||
}
|
||||
}
|
||||
node.setAttributeNS(XML_SCHEMA_INSTANCE_URI, 'xsi:schemaLocation', this.schemaLocation_);
|
||||
/** @type {module:ol/xml~NodeStackItem} */
|
||||
const context = {
|
||||
node: node,
|
||||
'srsName': options.srsName,
|
||||
'featureNS': options.featureNS ? options.featureNS : this.featureNS_,
|
||||
'featurePrefix': options.featurePrefix,
|
||||
'geometryName': options.geometryName,
|
||||
'filter': filter,
|
||||
'propertyNames': options.propertyNames ? options.propertyNames : []
|
||||
};
|
||||
assert(Array.isArray(options.featureTypes),
|
||||
11); // `options.featureTypes` should be an Array
|
||||
writeGetFeature(node, /** @type {!Array.<string>} */ (options.featureTypes), [context]);
|
||||
return node;
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode format as WFS `Transaction` and return the Node.
|
||||
*
|
||||
* @param {Array.<module:ol/Feature>} inserts The features to insert.
|
||||
* @param {Array.<module:ol/Feature>} updates The features to update.
|
||||
* @param {Array.<module:ol/Feature>} deletes The features to delete.
|
||||
* @param {module:ol/format/WFS~WriteTransactionOptions} options Write options.
|
||||
* @return {Node} Result.
|
||||
* @api
|
||||
*/
|
||||
writeTransaction(inserts, updates, deletes, options) {
|
||||
const objectStack = [];
|
||||
const node = createElementNS(WFSNS, 'Transaction');
|
||||
const version = options.version ? options.version : DEFAULT_VERSION;
|
||||
const gmlVersion = version === '1.0.0' ? 2 : 3;
|
||||
node.setAttribute('service', 'WFS');
|
||||
node.setAttribute('version', version);
|
||||
let baseObj;
|
||||
/** @type {module:ol/xml~NodeStackItem} */
|
||||
let obj;
|
||||
if (options) {
|
||||
baseObj = options.gmlOptions ? options.gmlOptions : {};
|
||||
if (options.handle) {
|
||||
node.setAttribute('handle', options.handle);
|
||||
}
|
||||
}
|
||||
const schemaLocation = SCHEMA_LOCATIONS[version];
|
||||
node.setAttributeNS(XML_SCHEMA_INSTANCE_URI, 'xsi:schemaLocation', schemaLocation);
|
||||
const featurePrefix = options.featurePrefix ? options.featurePrefix : FEATURE_PREFIX;
|
||||
if (inserts) {
|
||||
obj = {node: node, 'featureNS': options.featureNS,
|
||||
'featureType': options.featureType, 'featurePrefix': featurePrefix,
|
||||
'gmlVersion': gmlVersion, 'hasZ': options.hasZ, 'srsName': options.srsName};
|
||||
assign(obj, baseObj);
|
||||
pushSerializeAndPop(obj,
|
||||
TRANSACTION_SERIALIZERS,
|
||||
makeSimpleNodeFactory('Insert'), inserts,
|
||||
objectStack);
|
||||
}
|
||||
if (updates) {
|
||||
obj = {node: node, 'featureNS': options.featureNS,
|
||||
'featureType': options.featureType, 'featurePrefix': featurePrefix,
|
||||
'gmlVersion': gmlVersion, 'hasZ': options.hasZ, 'srsName': options.srsName};
|
||||
assign(obj, baseObj);
|
||||
pushSerializeAndPop(obj,
|
||||
TRANSACTION_SERIALIZERS,
|
||||
makeSimpleNodeFactory('Update'), updates,
|
||||
objectStack);
|
||||
}
|
||||
if (deletes) {
|
||||
pushSerializeAndPop({node: node, 'featureNS': options.featureNS,
|
||||
'featureType': options.featureType, 'featurePrefix': featurePrefix,
|
||||
'gmlVersion': gmlVersion, 'srsName': options.srsName},
|
||||
TRANSACTION_SERIALIZERS,
|
||||
makeSimpleNodeFactory('Delete'), deletes,
|
||||
objectStack);
|
||||
}
|
||||
if (options.nativeElements) {
|
||||
pushSerializeAndPop({node: node, 'featureNS': options.featureNS,
|
||||
'featureType': options.featureType, 'featurePrefix': featurePrefix,
|
||||
'gmlVersion': gmlVersion, 'srsName': options.srsName},
|
||||
TRANSACTION_SERIALIZERS,
|
||||
makeSimpleNodeFactory('Native'), options.nativeElements,
|
||||
objectStack);
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
readProjectionFromDocument(doc) {
|
||||
for (let n = doc.firstChild; n; n = n.nextSibling) {
|
||||
if (n.nodeType == Node.ELEMENT_NODE) {
|
||||
return this.readProjectionFromNode(n);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
readProjectionFromNode(node) {
|
||||
if (node.firstElementChild &&
|
||||
node.firstElementChild.firstElementChild) {
|
||||
node = node.firstElementChild.firstElementChild;
|
||||
for (let n = node.firstElementChild; n; n = n.nextElementSibling) {
|
||||
if (!(n.childNodes.length === 0 ||
|
||||
(n.childNodes.length === 1 &&
|
||||
n.firstChild.nodeType === 3))) {
|
||||
const objectStack = [{}];
|
||||
this.gmlFormat_.readGeometryElement(n, objectStack);
|
||||
return getProjection(objectStack.pop().srsName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
@@ -386,55 +591,6 @@ function readInsertResults(node, objectStack) {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @const
|
||||
* @type {Object.<string, Object.<string, module:ol/xml~Parser>>}
|
||||
*/
|
||||
const TRANSACTION_RESPONSE_PARSERS = {
|
||||
'http://www.opengis.net/wfs': {
|
||||
'TransactionSummary': makeObjectPropertySetter(
|
||||
readTransactionSummary, 'transactionSummary'),
|
||||
'InsertResults': makeObjectPropertySetter(
|
||||
readInsertResults, 'insertIds')
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {Document} doc Document.
|
||||
* @return {module:ol/format/WFS~TransactionResponse|undefined} Transaction response.
|
||||
*/
|
||||
WFS.prototype.readTransactionResponseFromDocument = function(doc) {
|
||||
for (let n = doc.firstChild; n; n = n.nextSibling) {
|
||||
if (n.nodeType == Node.ELEMENT_NODE) {
|
||||
return this.readTransactionResponseFromNode(n);
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {Node} node Node.
|
||||
* @return {module:ol/format/WFS~TransactionResponse|undefined} Transaction response.
|
||||
*/
|
||||
WFS.prototype.readTransactionResponseFromNode = function(node) {
|
||||
return pushParseAndPop(
|
||||
/** @type {module:ol/format/WFS~TransactionResponse} */({}),
|
||||
TRANSACTION_RESPONSE_PARSERS, node, []);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @type {Object.<string, Object.<string, module:ol/xml~Serializer>>}
|
||||
*/
|
||||
const QUERY_SERIALIZERS = {
|
||||
'http://www.opengis.net/wfs': {
|
||||
'PropertyName': makeChildAppender(writeStringTextNode)
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {Node} node Node.
|
||||
* @param {module:ol/Feature} feature Feature.
|
||||
@@ -507,20 +663,6 @@ function writeDelete(node, feature, objectStack) {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @type {Object.<string, Object.<string, module:ol/xml~Serializer>>}
|
||||
*/
|
||||
const TRANSACTION_SERIALIZERS = {
|
||||
'http://www.opengis.net/wfs': {
|
||||
'Insert': makeChildAppender(writeFeature),
|
||||
'Update': makeChildAppender(writeUpdate),
|
||||
'Delete': makeChildAppender(writeDelete),
|
||||
'Property': makeChildAppender(writeProperty),
|
||||
'Native': makeChildAppender(writeNative)
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {Node} node Node.
|
||||
* @param {module:ol/Feature} feature Feature.
|
||||
@@ -942,180 +1084,4 @@ function writeGetFeature(node, featureTypes, objectStack) {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Encode format as WFS `GetFeature` and return the Node.
|
||||
*
|
||||
* @param {module:ol/format/WFS~WriteGetFeatureOptions} options Options.
|
||||
* @return {Node} Result.
|
||||
* @api
|
||||
*/
|
||||
WFS.prototype.writeGetFeature = function(options) {
|
||||
const node = createElementNS(WFSNS, 'GetFeature');
|
||||
node.setAttribute('service', 'WFS');
|
||||
node.setAttribute('version', '1.1.0');
|
||||
let filter;
|
||||
if (options) {
|
||||
if (options.handle) {
|
||||
node.setAttribute('handle', options.handle);
|
||||
}
|
||||
if (options.outputFormat) {
|
||||
node.setAttribute('outputFormat', options.outputFormat);
|
||||
}
|
||||
if (options.maxFeatures !== undefined) {
|
||||
node.setAttribute('maxFeatures', options.maxFeatures);
|
||||
}
|
||||
if (options.resultType) {
|
||||
node.setAttribute('resultType', options.resultType);
|
||||
}
|
||||
if (options.startIndex !== undefined) {
|
||||
node.setAttribute('startIndex', options.startIndex);
|
||||
}
|
||||
if (options.count !== undefined) {
|
||||
node.setAttribute('count', options.count);
|
||||
}
|
||||
filter = options.filter;
|
||||
if (options.bbox) {
|
||||
assert(options.geometryName,
|
||||
12); // `options.geometryName` must also be provided when `options.bbox` is set
|
||||
const bbox = bboxFilter(
|
||||
/** @type {string} */ (options.geometryName), options.bbox, options.srsName);
|
||||
if (filter) {
|
||||
// if bbox and filter are both set, combine the two into a single filter
|
||||
filter = andFilter(filter, bbox);
|
||||
} else {
|
||||
filter = bbox;
|
||||
}
|
||||
}
|
||||
}
|
||||
node.setAttributeNS(XML_SCHEMA_INSTANCE_URI, 'xsi:schemaLocation', this.schemaLocation_);
|
||||
/** @type {module:ol/xml~NodeStackItem} */
|
||||
const context = {
|
||||
node: node,
|
||||
'srsName': options.srsName,
|
||||
'featureNS': options.featureNS ? options.featureNS : this.featureNS_,
|
||||
'featurePrefix': options.featurePrefix,
|
||||
'geometryName': options.geometryName,
|
||||
'filter': filter,
|
||||
'propertyNames': options.propertyNames ? options.propertyNames : []
|
||||
};
|
||||
assert(Array.isArray(options.featureTypes),
|
||||
11); // `options.featureTypes` should be an Array
|
||||
writeGetFeature(node, /** @type {!Array.<string>} */ (options.featureTypes), [context]);
|
||||
return node;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Encode format as WFS `Transaction` and return the Node.
|
||||
*
|
||||
* @param {Array.<module:ol/Feature>} inserts The features to insert.
|
||||
* @param {Array.<module:ol/Feature>} updates The features to update.
|
||||
* @param {Array.<module:ol/Feature>} deletes The features to delete.
|
||||
* @param {module:ol/format/WFS~WriteTransactionOptions} options Write options.
|
||||
* @return {Node} Result.
|
||||
* @api
|
||||
*/
|
||||
WFS.prototype.writeTransaction = function(inserts, updates, deletes, options) {
|
||||
const objectStack = [];
|
||||
const node = createElementNS(WFSNS, 'Transaction');
|
||||
const version = options.version ? options.version : DEFAULT_VERSION;
|
||||
const gmlVersion = version === '1.0.0' ? 2 : 3;
|
||||
node.setAttribute('service', 'WFS');
|
||||
node.setAttribute('version', version);
|
||||
let baseObj;
|
||||
/** @type {module:ol/xml~NodeStackItem} */
|
||||
let obj;
|
||||
if (options) {
|
||||
baseObj = options.gmlOptions ? options.gmlOptions : {};
|
||||
if (options.handle) {
|
||||
node.setAttribute('handle', options.handle);
|
||||
}
|
||||
}
|
||||
const schemaLocation = SCHEMA_LOCATIONS[version];
|
||||
node.setAttributeNS(XML_SCHEMA_INSTANCE_URI, 'xsi:schemaLocation', schemaLocation);
|
||||
const featurePrefix = options.featurePrefix ? options.featurePrefix : FEATURE_PREFIX;
|
||||
if (inserts) {
|
||||
obj = {node: node, 'featureNS': options.featureNS,
|
||||
'featureType': options.featureType, 'featurePrefix': featurePrefix,
|
||||
'gmlVersion': gmlVersion, 'hasZ': options.hasZ, 'srsName': options.srsName};
|
||||
assign(obj, baseObj);
|
||||
pushSerializeAndPop(obj,
|
||||
TRANSACTION_SERIALIZERS,
|
||||
makeSimpleNodeFactory('Insert'), inserts,
|
||||
objectStack);
|
||||
}
|
||||
if (updates) {
|
||||
obj = {node: node, 'featureNS': options.featureNS,
|
||||
'featureType': options.featureType, 'featurePrefix': featurePrefix,
|
||||
'gmlVersion': gmlVersion, 'hasZ': options.hasZ, 'srsName': options.srsName};
|
||||
assign(obj, baseObj);
|
||||
pushSerializeAndPop(obj,
|
||||
TRANSACTION_SERIALIZERS,
|
||||
makeSimpleNodeFactory('Update'), updates,
|
||||
objectStack);
|
||||
}
|
||||
if (deletes) {
|
||||
pushSerializeAndPop({node: node, 'featureNS': options.featureNS,
|
||||
'featureType': options.featureType, 'featurePrefix': featurePrefix,
|
||||
'gmlVersion': gmlVersion, 'srsName': options.srsName},
|
||||
TRANSACTION_SERIALIZERS,
|
||||
makeSimpleNodeFactory('Delete'), deletes,
|
||||
objectStack);
|
||||
}
|
||||
if (options.nativeElements) {
|
||||
pushSerializeAndPop({node: node, 'featureNS': options.featureNS,
|
||||
'featureType': options.featureType, 'featurePrefix': featurePrefix,
|
||||
'gmlVersion': gmlVersion, 'srsName': options.srsName},
|
||||
TRANSACTION_SERIALIZERS,
|
||||
makeSimpleNodeFactory('Native'), options.nativeElements,
|
||||
objectStack);
|
||||
}
|
||||
return node;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Read the projection from a WFS source.
|
||||
*
|
||||
* @function
|
||||
* @param {Document|Node|Object|string} source Source.
|
||||
* @return {?module:ol/proj/Projection} Projection.
|
||||
* @api
|
||||
*/
|
||||
WFS.prototype.readProjection;
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
WFS.prototype.readProjectionFromDocument = function(doc) {
|
||||
for (let n = doc.firstChild; n; n = n.nextSibling) {
|
||||
if (n.nodeType == Node.ELEMENT_NODE) {
|
||||
return this.readProjectionFromNode(n);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
WFS.prototype.readProjectionFromNode = function(node) {
|
||||
if (node.firstElementChild &&
|
||||
node.firstElementChild.firstElementChild) {
|
||||
node = node.firstElementChild.firstElementChild;
|
||||
for (let n = node.firstElementChild; n; n = n.nextElementSibling) {
|
||||
if (!(n.childNodes.length === 0 ||
|
||||
(n.childNodes.length === 1 &&
|
||||
n.firstChild.nodeType === 3))) {
|
||||
const objectStack = [{}];
|
||||
this.gmlFormat_.readGeometryElement(n, objectStack);
|
||||
return getProjection(objectStack.pop().srsName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
export default WFS;
|
||||
|
||||
1226
src/ol/format/WKT.js
1226
src/ol/format/WKT.js
File diff suppressed because it is too large
Load Diff
@@ -1,7 +1,6 @@
|
||||
/**
|
||||
* @module ol/format/WMSCapabilities
|
||||
*/
|
||||
import {inherits} from '../util.js';
|
||||
import {readHref} from '../format/XLink.js';
|
||||
import XML from '../format/XML.js';
|
||||
import {readDecimalString, readString, readNonNegativeInteger, readDecimal, readBooleanString, readNonNegativeIntegerString} from '../format/xsd.js';
|
||||
@@ -9,27 +8,6 @@ import {makeArrayPusher, makeObjectPropertyPusher, makeObjectPropertySetter,
|
||||
makeStructureNS, pushParseAndPop} from '../xml.js';
|
||||
|
||||
|
||||
/**
|
||||
* @classdesc
|
||||
* Format for reading WMS capabilities data
|
||||
*
|
||||
* @constructor
|
||||
* @extends {module:ol/format/XML}
|
||||
* @api
|
||||
*/
|
||||
const WMSCapabilities = function() {
|
||||
|
||||
XML.call(this);
|
||||
|
||||
/**
|
||||
* @type {string|undefined}
|
||||
*/
|
||||
this.version = undefined;
|
||||
};
|
||||
|
||||
inherits(WMSCapabilities, XML);
|
||||
|
||||
|
||||
/**
|
||||
* @const
|
||||
* @type {Array.<null|string>}
|
||||
@@ -63,6 +41,47 @@ const CAPABILITY_PARSERS = makeStructureNS(
|
||||
});
|
||||
|
||||
|
||||
/**
|
||||
* @classdesc
|
||||
* Format for reading WMS capabilities data
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
class WMSCapabilities extends XML {
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
/**
|
||||
* @type {string|undefined}
|
||||
*/
|
||||
this.version = undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
readFromDocument(doc) {
|
||||
for (let n = doc.firstChild; n; n = n.nextSibling) {
|
||||
if (n.nodeType == Node.ELEMENT_NODE) {
|
||||
return this.readFromNode(n);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
readFromNode(node) {
|
||||
this.version = node.getAttribute('version').trim();
|
||||
const wmsCapabilityObject = pushParseAndPop({
|
||||
'version': this.version
|
||||
}, PARSERS, node, []);
|
||||
return wmsCapabilityObject ? wmsCapabilityObject : null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @const
|
||||
* @type {Object.<string, Object.<string, module:ol/xml~Parser>>}
|
||||
@@ -266,42 +285,6 @@ const KEYWORDLIST_PARSERS = makeStructureNS(
|
||||
});
|
||||
|
||||
|
||||
/**
|
||||
* Read a WMS capabilities document.
|
||||
*
|
||||
* @function
|
||||
* @param {Document|Node|string} source The XML source.
|
||||
* @return {Object} An object representing the WMS capabilities.
|
||||
* @api
|
||||
*/
|
||||
WMSCapabilities.prototype.read;
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
WMSCapabilities.prototype.readFromDocument = function(doc) {
|
||||
for (let n = doc.firstChild; n; n = n.nextSibling) {
|
||||
if (n.nodeType == Node.ELEMENT_NODE) {
|
||||
return this.readFromNode(n);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
WMSCapabilities.prototype.readFromNode = function(node) {
|
||||
this.version = node.getAttribute('version').trim();
|
||||
const wmsCapabilityObject = pushParseAndPop({
|
||||
'version': this.version
|
||||
}, PARSERS, node, []);
|
||||
return wmsCapabilityObject ? wmsCapabilityObject : null;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {Node} node Node.
|
||||
* @param {Array.<*>} objectStack Object stack.
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
/**
|
||||
* @module ol/format/WMSGetFeatureInfo
|
||||
*/
|
||||
import {inherits} from '../util.js';
|
||||
import {extend, includes} from '../array.js';
|
||||
import GML2 from '../format/GML2.js';
|
||||
import XMLFeature from '../format/XMLFeature.js';
|
||||
@@ -15,46 +14,6 @@ import {makeArrayPusher, makeStructureNS, pushParseAndPop} from '../xml.js';
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* @classdesc
|
||||
* Format for reading WMSGetFeatureInfo format. It uses
|
||||
* {@link module:ol/format/GML2~GML2} to read features.
|
||||
*
|
||||
* @constructor
|
||||
* @extends {module:ol/format/XMLFeature}
|
||||
* @param {module:ol/format/WMSGetFeatureInfo~Options=} opt_options Options.
|
||||
* @api
|
||||
*/
|
||||
const WMSGetFeatureInfo = function(opt_options) {
|
||||
|
||||
const options = opt_options ? opt_options : {};
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {string}
|
||||
*/
|
||||
this.featureNS_ = 'http://mapserver.gis.umn.edu/mapserver';
|
||||
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {module:ol/format/GML2}
|
||||
*/
|
||||
this.gmlFormat_ = new GML2();
|
||||
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {Array.<string>}
|
||||
*/
|
||||
this.layers_ = options.layers ? options.layers : null;
|
||||
|
||||
XMLFeature.call(this);
|
||||
};
|
||||
|
||||
inherits(WMSGetFeatureInfo, XMLFeature);
|
||||
|
||||
|
||||
/**
|
||||
* @const
|
||||
* @type {string}
|
||||
@@ -70,122 +29,145 @@ const layerIdentifier = '_layer';
|
||||
|
||||
|
||||
/**
|
||||
* @return {Array.<string>} layers
|
||||
*/
|
||||
WMSGetFeatureInfo.prototype.getLayers = function() {
|
||||
return this.layers_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {Array.<string>} layers Layers to parse.
|
||||
*/
|
||||
WMSGetFeatureInfo.prototype.setLayers = function(layers) {
|
||||
this.layers_ = layers;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {Node} node Node.
|
||||
* @param {Array.<*>} objectStack Object stack.
|
||||
* @return {Array.<module:ol/Feature>} Features.
|
||||
* @private
|
||||
*/
|
||||
WMSGetFeatureInfo.prototype.readFeatures_ = function(node, objectStack) {
|
||||
node.setAttribute('namespaceURI', this.featureNS_);
|
||||
const localName = node.localName;
|
||||
/** @type {Array.<module:ol/Feature>} */
|
||||
let features = [];
|
||||
if (node.childNodes.length === 0) {
|
||||
return features;
|
||||
}
|
||||
if (localName == 'msGMLOutput') {
|
||||
for (let i = 0, ii = node.childNodes.length; i < ii; i++) {
|
||||
const layer = node.childNodes[i];
|
||||
if (layer.nodeType !== Node.ELEMENT_NODE) {
|
||||
continue;
|
||||
}
|
||||
const context = objectStack[0];
|
||||
|
||||
const toRemove = layerIdentifier;
|
||||
const layerName = layer.localName.replace(toRemove, '');
|
||||
|
||||
if (this.layers_ && !includes(this.layers_, layerName)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const featureType = layerName +
|
||||
featureIdentifier;
|
||||
|
||||
context['featureType'] = featureType;
|
||||
context['featureNS'] = this.featureNS_;
|
||||
|
||||
const parsers = {};
|
||||
parsers[featureType] = makeArrayPusher(
|
||||
this.gmlFormat_.readFeatureElement, this.gmlFormat_);
|
||||
const parsersNS = makeStructureNS(
|
||||
[context['featureNS'], null], parsers);
|
||||
layer.setAttribute('namespaceURI', this.featureNS_);
|
||||
const layerFeatures = pushParseAndPop(
|
||||
[], parsersNS, layer, objectStack, this.gmlFormat_);
|
||||
if (layerFeatures) {
|
||||
extend(features, layerFeatures);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (localName == 'FeatureCollection') {
|
||||
const gmlFeatures = pushParseAndPop([],
|
||||
this.gmlFormat_.FEATURE_COLLECTION_PARSERS, node,
|
||||
[{}], this.gmlFormat_);
|
||||
if (gmlFeatures) {
|
||||
features = gmlFeatures;
|
||||
}
|
||||
}
|
||||
return features;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Read all features from a WMSGetFeatureInfo response.
|
||||
* @classdesc
|
||||
* Format for reading WMSGetFeatureInfo format. It uses
|
||||
* {@link module:ol/format/GML2~GML2} to read features.
|
||||
*
|
||||
* @function
|
||||
* @param {Document|Node|Object|string} source Source.
|
||||
* @param {module:ol/format/Feature~ReadOptions=} opt_options Options.
|
||||
* @return {Array.<module:ol/Feature>} Features.
|
||||
* @api
|
||||
*/
|
||||
WMSGetFeatureInfo.prototype.readFeatures;
|
||||
class WMSGetFeatureInfo extends XMLFeature {
|
||||
|
||||
/**
|
||||
* @param {module:ol/format/WMSGetFeatureInfo~Options=} opt_options Options.
|
||||
*/
|
||||
constructor(opt_options) {
|
||||
super();
|
||||
|
||||
const options = opt_options ? opt_options : {};
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {string}
|
||||
*/
|
||||
this.featureNS_ = 'http://mapserver.gis.umn.edu/mapserver';
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
WMSGetFeatureInfo.prototype.readFeaturesFromNode = function(node, opt_options) {
|
||||
const options = {};
|
||||
if (opt_options) {
|
||||
assign(options, this.getReadOptions(node, opt_options));
|
||||
/**
|
||||
* @private
|
||||
* @type {module:ol/format/GML2}
|
||||
*/
|
||||
this.gmlFormat_ = new GML2();
|
||||
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {Array.<string>}
|
||||
*/
|
||||
this.layers_ = options.layers ? options.layers : null;
|
||||
}
|
||||
return this.readFeatures_(node, [options]);
|
||||
};
|
||||
|
||||
/**
|
||||
* @return {Array.<string>} layers
|
||||
*/
|
||||
getLayers() {
|
||||
return this.layers_;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Array.<string>} layers Layers to parse.
|
||||
*/
|
||||
setLayers(layers) {
|
||||
this.layers_ = layers;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Node} node Node.
|
||||
* @param {Array.<*>} objectStack Object stack.
|
||||
* @return {Array.<module:ol/Feature>} Features.
|
||||
* @private
|
||||
*/
|
||||
readFeatures_(node, objectStack) {
|
||||
node.setAttribute('namespaceURI', this.featureNS_);
|
||||
const localName = node.localName;
|
||||
/** @type {Array.<module:ol/Feature>} */
|
||||
let features = [];
|
||||
if (node.childNodes.length === 0) {
|
||||
return features;
|
||||
}
|
||||
if (localName == 'msGMLOutput') {
|
||||
for (let i = 0, ii = node.childNodes.length; i < ii; i++) {
|
||||
const layer = node.childNodes[i];
|
||||
if (layer.nodeType !== Node.ELEMENT_NODE) {
|
||||
continue;
|
||||
}
|
||||
const context = objectStack[0];
|
||||
|
||||
const toRemove = layerIdentifier;
|
||||
const layerName = layer.localName.replace(toRemove, '');
|
||||
|
||||
if (this.layers_ && !includes(this.layers_, layerName)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const featureType = layerName +
|
||||
featureIdentifier;
|
||||
|
||||
context['featureType'] = featureType;
|
||||
context['featureNS'] = this.featureNS_;
|
||||
|
||||
const parsers = {};
|
||||
parsers[featureType] = makeArrayPusher(
|
||||
this.gmlFormat_.readFeatureElement, this.gmlFormat_);
|
||||
const parsersNS = makeStructureNS(
|
||||
[context['featureNS'], null], parsers);
|
||||
layer.setAttribute('namespaceURI', this.featureNS_);
|
||||
const layerFeatures = pushParseAndPop(
|
||||
[], parsersNS, layer, objectStack, this.gmlFormat_);
|
||||
if (layerFeatures) {
|
||||
extend(features, layerFeatures);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (localName == 'FeatureCollection') {
|
||||
const gmlFeatures = pushParseAndPop([],
|
||||
this.gmlFormat_.FEATURE_COLLECTION_PARSERS, node,
|
||||
[{}], this.gmlFormat_);
|
||||
if (gmlFeatures) {
|
||||
features = gmlFeatures;
|
||||
}
|
||||
}
|
||||
return features;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
readFeaturesFromNode(node, opt_options) {
|
||||
const options = {};
|
||||
if (opt_options) {
|
||||
assign(options, this.getReadOptions(node, opt_options));
|
||||
}
|
||||
return this.readFeatures_(node, [options]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Not implemented.
|
||||
* @inheritDoc
|
||||
*/
|
||||
writeFeatureNode(feature, opt_options) {}
|
||||
|
||||
/**
|
||||
* Not implemented.
|
||||
* @inheritDoc
|
||||
*/
|
||||
writeFeaturesNode(features, opt_options) {}
|
||||
|
||||
/**
|
||||
* Not implemented.
|
||||
* @inheritDoc
|
||||
*/
|
||||
writeGeometryNode(geometry, opt_options) {}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Not implemented.
|
||||
* @inheritDoc
|
||||
*/
|
||||
WMSGetFeatureInfo.prototype.writeFeatureNode = function(feature, opt_options) {};
|
||||
|
||||
|
||||
/**
|
||||
* Not implemented.
|
||||
* @inheritDoc
|
||||
*/
|
||||
WMSGetFeatureInfo.prototype.writeFeaturesNode = function(features, opt_options) {};
|
||||
|
||||
|
||||
/**
|
||||
* Not implemented.
|
||||
* @inheritDoc
|
||||
*/
|
||||
WMSGetFeatureInfo.prototype.writeGeometryNode = function(geometry, opt_options) {};
|
||||
export default WMSGetFeatureInfo;
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
/**
|
||||
* @module ol/format/WMTSCapabilities
|
||||
*/
|
||||
import {inherits} from '../util.js';
|
||||
import {boundingExtent} from '../extent.js';
|
||||
import OWS from '../format/OWS.js';
|
||||
import {readHref} from '../format/XLink.js';
|
||||
@@ -10,26 +9,6 @@ import {readString, readNonNegativeInteger, readDecimal} from '../format/xsd.js'
|
||||
import {pushParseAndPop, makeStructureNS,
|
||||
makeObjectPropertySetter, makeObjectPropertyPusher, makeArrayPusher} from '../xml.js';
|
||||
|
||||
/**
|
||||
* @classdesc
|
||||
* Format for reading WMTS capabilities data.
|
||||
*
|
||||
* @constructor
|
||||
* @extends {module:ol/format/XML}
|
||||
* @api
|
||||
*/
|
||||
const WMTSCapabilities = function() {
|
||||
XML.call(this);
|
||||
|
||||
/**
|
||||
* @type {module:ol/format/OWS}
|
||||
* @private
|
||||
*/
|
||||
this.owsParser_ = new OWS();
|
||||
};
|
||||
|
||||
inherits(WMTSCapabilities, XML);
|
||||
|
||||
|
||||
/**
|
||||
* @const
|
||||
@@ -61,6 +40,51 @@ const PARSERS = makeStructureNS(
|
||||
});
|
||||
|
||||
|
||||
/**
|
||||
* @classdesc
|
||||
* Format for reading WMTS capabilities data.
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
class WMTSCapabilities extends XML {
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
/**
|
||||
* @type {module:ol/format/OWS}
|
||||
* @private
|
||||
*/
|
||||
this.owsParser_ = new OWS();
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
readFromDocument(doc) {
|
||||
for (let n = doc.firstChild; n; n = n.nextSibling) {
|
||||
if (n.nodeType == Node.ELEMENT_NODE) {
|
||||
return this.readFromNode(n);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
readFromNode(node) {
|
||||
const version = node.getAttribute('version').trim();
|
||||
let WMTSCapabilityObject = this.owsParser_.readFromNode(node);
|
||||
if (!WMTSCapabilityObject) {
|
||||
return null;
|
||||
}
|
||||
WMTSCapabilityObject['version'] = version;
|
||||
WMTSCapabilityObject = pushParseAndPop(WMTSCapabilityObject, PARSERS, node, []);
|
||||
return WMTSCapabilityObject ? WMTSCapabilityObject : null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @const
|
||||
* @type {Object.<string, Object.<string, module:ol/xml~Parser>>}
|
||||
@@ -193,45 +217,6 @@ const TM_PARSERS = makeStructureNS(
|
||||
}));
|
||||
|
||||
|
||||
/**
|
||||
* Read a WMTS capabilities document.
|
||||
*
|
||||
* @function
|
||||
* @param {Document|Node|string} source The XML source.
|
||||
* @return {Object} An object representing the WMTS capabilities.
|
||||
* @api
|
||||
*/
|
||||
WMTSCapabilities.prototype.read;
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
WMTSCapabilities.prototype.readFromDocument = function(doc) {
|
||||
for (let n = doc.firstChild; n; n = n.nextSibling) {
|
||||
if (n.nodeType == Node.ELEMENT_NODE) {
|
||||
return this.readFromNode(n);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
WMTSCapabilities.prototype.readFromNode = function(node) {
|
||||
const version = node.getAttribute('version').trim();
|
||||
let WMTSCapabilityObject = this.owsParser_.readFromNode(node);
|
||||
if (!WMTSCapabilityObject) {
|
||||
return null;
|
||||
}
|
||||
WMTSCapabilityObject['version'] = version;
|
||||
WMTSCapabilityObject = pushParseAndPop(WMTSCapabilityObject, PARSERS, node, []);
|
||||
return WMTSCapabilityObject ? WMTSCapabilityObject : null;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {Node} node Node.
|
||||
* @param {Array.<*>} objectStack Object stack.
|
||||
|
||||
@@ -7,44 +7,42 @@ import {isDocument, isNode, parse} from '../xml.js';
|
||||
* @classdesc
|
||||
* Generic format for reading non-feature XML data
|
||||
*
|
||||
* @constructor
|
||||
* @abstract
|
||||
* @struct
|
||||
*/
|
||||
const XML = function() {
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {Document|Node|string} source Source.
|
||||
* @return {Object} The parsed result.
|
||||
*/
|
||||
XML.prototype.read = function(source) {
|
||||
if (isDocument(source)) {
|
||||
return this.readFromDocument(/** @type {Document} */ (source));
|
||||
} else if (isNode(source)) {
|
||||
return this.readFromNode(/** @type {Node} */ (source));
|
||||
} else if (typeof source === 'string') {
|
||||
const doc = parse(source);
|
||||
return this.readFromDocument(doc);
|
||||
} else {
|
||||
return null;
|
||||
class XML {
|
||||
/**
|
||||
* Read the source document.
|
||||
*
|
||||
* @param {Document|Node|string} source The XML source.
|
||||
* @return {Object} An object representing the source.
|
||||
* @api
|
||||
*/
|
||||
read(source) {
|
||||
if (isDocument(source)) {
|
||||
return this.readFromDocument(/** @type {Document} */ (source));
|
||||
} else if (isNode(source)) {
|
||||
return this.readFromNode(/** @type {Node} */ (source));
|
||||
} else if (typeof source === 'string') {
|
||||
const doc = parse(source);
|
||||
return this.readFromDocument(doc);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @abstract
|
||||
* @param {Document} doc Document.
|
||||
* @return {Object} Object
|
||||
*/
|
||||
readFromDocument(doc) {}
|
||||
|
||||
/**
|
||||
* @abstract
|
||||
* @param {Document} doc Document.
|
||||
* @return {Object} Object
|
||||
*/
|
||||
XML.prototype.readFromDocument = function(doc) {};
|
||||
/**
|
||||
* @abstract
|
||||
* @param {Node} node Node.
|
||||
* @return {Object} Object
|
||||
*/
|
||||
readFromNode(node) {}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @abstract
|
||||
* @param {Node} node Node.
|
||||
* @return {Object} Object
|
||||
*/
|
||||
XML.prototype.readFromNode = function(node) {};
|
||||
export default XML;
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
/**
|
||||
* @module ol/format/XMLFeature
|
||||
*/
|
||||
import {inherits} from '../util.js';
|
||||
import {extend} from '../array.js';
|
||||
import FeatureFormat from '../format/Feature.js';
|
||||
import FormatType from '../format/FormatType.js';
|
||||
@@ -13,251 +12,251 @@ import {isDocument, isNode, parse} from '../xml.js';
|
||||
* instantiated in apps.
|
||||
* Base class for XML feature formats.
|
||||
*
|
||||
* @constructor
|
||||
* @abstract
|
||||
* @extends {module:ol/format/Feature}
|
||||
*/
|
||||
const XMLFeature = function() {
|
||||
class XMLFeature extends FeatureFormat {
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
/**
|
||||
* @type {XMLSerializer}
|
||||
* @private
|
||||
*/
|
||||
this.xmlSerializer_ = new XMLSerializer();
|
||||
}
|
||||
|
||||
/**
|
||||
* @type {XMLSerializer}
|
||||
* @private
|
||||
* @inheritDoc
|
||||
*/
|
||||
this.xmlSerializer_ = new XMLSerializer();
|
||||
|
||||
FeatureFormat.call(this);
|
||||
};
|
||||
|
||||
inherits(XMLFeature, FeatureFormat);
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
XMLFeature.prototype.getType = function() {
|
||||
return FormatType.XML;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
XMLFeature.prototype.readFeature = function(source, opt_options) {
|
||||
if (isDocument(source)) {
|
||||
return this.readFeatureFromDocument(/** @type {Document} */ (source), opt_options);
|
||||
} else if (isNode(source)) {
|
||||
return this.readFeatureFromNode(/** @type {Node} */ (source), opt_options);
|
||||
} else if (typeof source === 'string') {
|
||||
const doc = parse(source);
|
||||
return this.readFeatureFromDocument(doc, opt_options);
|
||||
} else {
|
||||
return null;
|
||||
getType() {
|
||||
return FormatType.XML;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {Document} doc Document.
|
||||
* @param {module:ol/format/Feature~ReadOptions=} opt_options Options.
|
||||
* @return {module:ol/Feature} Feature.
|
||||
*/
|
||||
XMLFeature.prototype.readFeatureFromDocument = function(doc, opt_options) {
|
||||
const features = this.readFeaturesFromDocument(doc, opt_options);
|
||||
if (features.length > 0) {
|
||||
return features[0];
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {Node} node Node.
|
||||
* @param {module:ol/format/Feature~ReadOptions=} opt_options Options.
|
||||
* @return {module:ol/Feature} Feature.
|
||||
*/
|
||||
XMLFeature.prototype.readFeatureFromNode = function(node, opt_options) {
|
||||
return null; // not implemented
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
XMLFeature.prototype.readFeatures = function(source, opt_options) {
|
||||
if (isDocument(source)) {
|
||||
return this.readFeaturesFromDocument(
|
||||
/** @type {Document} */ (source), opt_options);
|
||||
} else if (isNode(source)) {
|
||||
return this.readFeaturesFromNode(/** @type {Node} */ (source), opt_options);
|
||||
} else if (typeof source === 'string') {
|
||||
const doc = parse(source);
|
||||
return this.readFeaturesFromDocument(doc, opt_options);
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {Document} doc Document.
|
||||
* @param {module:ol/format/Feature~ReadOptions=} opt_options Options.
|
||||
* @protected
|
||||
* @return {Array.<module:ol/Feature>} Features.
|
||||
*/
|
||||
XMLFeature.prototype.readFeaturesFromDocument = function(doc, opt_options) {
|
||||
/** @type {Array.<module:ol/Feature>} */
|
||||
const features = [];
|
||||
for (let n = doc.firstChild; n; n = n.nextSibling) {
|
||||
if (n.nodeType == Node.ELEMENT_NODE) {
|
||||
extend(features, this.readFeaturesFromNode(n, opt_options));
|
||||
/**
|
||||
* Read a single feature.
|
||||
*
|
||||
* @param {Document|Node|Object|string} source Source.
|
||||
* @param {module:ol/format/Feature~ReadOptions=} opt_options Read options.
|
||||
* @return {module:ol/Feature} Feature.
|
||||
* @api
|
||||
*/
|
||||
readFeature(source, opt_options) {
|
||||
if (isDocument(source)) {
|
||||
return this.readFeatureFromDocument(/** @type {Document} */ (source), opt_options);
|
||||
} else if (isNode(source)) {
|
||||
return this.readFeatureFromNode(/** @type {Node} */ (source), opt_options);
|
||||
} else if (typeof source === 'string') {
|
||||
const doc = parse(source);
|
||||
return this.readFeatureFromDocument(doc, opt_options);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return features;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @abstract
|
||||
* @param {Node} node Node.
|
||||
* @param {module:ol/format/Feature~ReadOptions=} opt_options Options.
|
||||
* @protected
|
||||
* @return {Array.<module:ol/Feature>} Features.
|
||||
*/
|
||||
XMLFeature.prototype.readFeaturesFromNode = function(node, opt_options) {};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
XMLFeature.prototype.readGeometry = function(source, opt_options) {
|
||||
if (isDocument(source)) {
|
||||
return this.readGeometryFromDocument(
|
||||
/** @type {Document} */ (source), opt_options);
|
||||
} else if (isNode(source)) {
|
||||
return this.readGeometryFromNode(/** @type {Node} */ (source), opt_options);
|
||||
} else if (typeof source === 'string') {
|
||||
const doc = parse(source);
|
||||
return this.readGeometryFromDocument(doc, opt_options);
|
||||
} else {
|
||||
return null;
|
||||
/**
|
||||
* @param {Document} doc Document.
|
||||
* @param {module:ol/format/Feature~ReadOptions=} opt_options Options.
|
||||
* @return {module:ol/Feature} Feature.
|
||||
*/
|
||||
readFeatureFromDocument(doc, opt_options) {
|
||||
const features = this.readFeaturesFromDocument(doc, opt_options);
|
||||
if (features.length > 0) {
|
||||
return features[0];
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {Document} doc Document.
|
||||
* @param {module:ol/format/Feature~ReadOptions=} opt_options Options.
|
||||
* @protected
|
||||
* @return {module:ol/geom/Geometry} Geometry.
|
||||
*/
|
||||
XMLFeature.prototype.readGeometryFromDocument = function(doc, opt_options) {
|
||||
return null; // not implemented
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {Node} node Node.
|
||||
* @param {module:ol/format/Feature~ReadOptions=} opt_options Options.
|
||||
* @protected
|
||||
* @return {module:ol/geom/Geometry} Geometry.
|
||||
*/
|
||||
XMLFeature.prototype.readGeometryFromNode = function(node, opt_options) {
|
||||
return null; // not implemented
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
XMLFeature.prototype.readProjection = function(source) {
|
||||
if (isDocument(source)) {
|
||||
return this.readProjectionFromDocument(/** @type {Document} */ (source));
|
||||
} else if (isNode(source)) {
|
||||
return this.readProjectionFromNode(/** @type {Node} */ (source));
|
||||
} else if (typeof source === 'string') {
|
||||
const doc = parse(source);
|
||||
return this.readProjectionFromDocument(doc);
|
||||
} else {
|
||||
return null;
|
||||
/**
|
||||
* @param {Node} node Node.
|
||||
* @param {module:ol/format/Feature~ReadOptions=} opt_options Options.
|
||||
* @return {module:ol/Feature} Feature.
|
||||
*/
|
||||
readFeatureFromNode(node, opt_options) {
|
||||
return null; // not implemented
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Read all features from a feature collection.
|
||||
*
|
||||
* @function
|
||||
* @param {Document|Node|Object|string} source Source.
|
||||
* @param {module:ol/format/Feature~ReadOptions=} opt_options Options.
|
||||
* @return {Array.<module:ol/Feature>} Features.
|
||||
* @api
|
||||
*/
|
||||
readFeatures(source, opt_options) {
|
||||
if (isDocument(source)) {
|
||||
return this.readFeaturesFromDocument(
|
||||
/** @type {Document} */ (source), opt_options);
|
||||
} else if (isNode(source)) {
|
||||
return this.readFeaturesFromNode(/** @type {Node} */ (source), opt_options);
|
||||
} else if (typeof source === 'string') {
|
||||
const doc = parse(source);
|
||||
return this.readFeaturesFromDocument(doc, opt_options);
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Document} doc Document.
|
||||
* @param {module:ol/format/Feature~ReadOptions=} opt_options Options.
|
||||
* @protected
|
||||
* @return {Array.<module:ol/Feature>} Features.
|
||||
*/
|
||||
readFeaturesFromDocument(doc, opt_options) {
|
||||
/** @type {Array.<module:ol/Feature>} */
|
||||
const features = [];
|
||||
for (let n = doc.firstChild; n; n = n.nextSibling) {
|
||||
if (n.nodeType == Node.ELEMENT_NODE) {
|
||||
extend(features, this.readFeaturesFromNode(n, opt_options));
|
||||
}
|
||||
}
|
||||
return features;
|
||||
}
|
||||
|
||||
/**
|
||||
* @abstract
|
||||
* @param {Node} node Node.
|
||||
* @param {module:ol/format/Feature~ReadOptions=} opt_options Options.
|
||||
* @protected
|
||||
* @return {Array.<module:ol/Feature>} Features.
|
||||
*/
|
||||
readFeaturesFromNode(node, opt_options) {}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
readGeometry(source, opt_options) {
|
||||
if (isDocument(source)) {
|
||||
return this.readGeometryFromDocument(
|
||||
/** @type {Document} */ (source), opt_options);
|
||||
} else if (isNode(source)) {
|
||||
return this.readGeometryFromNode(/** @type {Node} */ (source), opt_options);
|
||||
} else if (typeof source === 'string') {
|
||||
const doc = parse(source);
|
||||
return this.readGeometryFromDocument(doc, opt_options);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Document} doc Document.
|
||||
* @param {module:ol/format/Feature~ReadOptions=} opt_options Options.
|
||||
* @protected
|
||||
* @return {module:ol/geom/Geometry} Geometry.
|
||||
*/
|
||||
readGeometryFromDocument(doc, opt_options) {
|
||||
return null; // not implemented
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Node} node Node.
|
||||
* @param {module:ol/format/Feature~ReadOptions=} opt_options Options.
|
||||
* @protected
|
||||
* @return {module:ol/geom/Geometry} Geometry.
|
||||
*/
|
||||
readGeometryFromNode(node, opt_options) {
|
||||
return null; // not implemented
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the projection from the source.
|
||||
*
|
||||
* @param {Document|Node|Object|string} source Source.
|
||||
* @return {module:ol/proj/Projection} Projection.
|
||||
* @api
|
||||
*/
|
||||
readProjection(source) {
|
||||
if (isDocument(source)) {
|
||||
return this.readProjectionFromDocument(/** @type {Document} */ (source));
|
||||
} else if (isNode(source)) {
|
||||
return this.readProjectionFromNode(/** @type {Node} */ (source));
|
||||
} else if (typeof source === 'string') {
|
||||
const doc = parse(source);
|
||||
return this.readProjectionFromDocument(doc);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Document} doc Document.
|
||||
* @protected
|
||||
* @return {module:ol/proj/Projection} Projection.
|
||||
*/
|
||||
readProjectionFromDocument(doc) {
|
||||
return this.dataProjection;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Node} node Node.
|
||||
* @protected
|
||||
* @return {module:ol/proj/Projection} Projection.
|
||||
*/
|
||||
readProjectionFromNode(node) {
|
||||
return this.dataProjection;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
writeFeature(feature, opt_options) {
|
||||
const node = this.writeFeatureNode(feature, opt_options);
|
||||
return this.xmlSerializer_.serializeToString(node);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {module:ol/Feature} feature Feature.
|
||||
* @param {module:ol/format/Feature~WriteOptions=} opt_options Options.
|
||||
* @protected
|
||||
* @return {Node} Node.
|
||||
*/
|
||||
writeFeatureNode(feature, opt_options) {
|
||||
return null; // not implemented
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode an array of features as string.
|
||||
*
|
||||
* @param {Array.<module:ol/Feature>} features Features.
|
||||
* @param {module:ol/format/Feature~WriteOptions=} opt_options Write options.
|
||||
* @return {string} Result.
|
||||
* @api
|
||||
*/
|
||||
writeFeatures(features, opt_options) {
|
||||
const node = this.writeFeaturesNode(features, opt_options);
|
||||
return this.xmlSerializer_.serializeToString(node);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Array.<module:ol/Feature>} features Features.
|
||||
* @param {module:ol/format/Feature~WriteOptions=} opt_options Options.
|
||||
* @return {Node} Node.
|
||||
*/
|
||||
writeFeaturesNode(features, opt_options) {
|
||||
return null; // not implemented
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
writeGeometry(geometry, opt_options) {
|
||||
const node = this.writeGeometryNode(geometry, opt_options);
|
||||
return this.xmlSerializer_.serializeToString(node);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {module:ol/geom/Geometry} geometry Geometry.
|
||||
* @param {module:ol/format/Feature~WriteOptions=} opt_options Options.
|
||||
* @return {Node} Node.
|
||||
*/
|
||||
writeGeometryNode(geometry, opt_options) {
|
||||
return null; // not implemented
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param {Document} doc Document.
|
||||
* @protected
|
||||
* @return {module:ol/proj/Projection} Projection.
|
||||
*/
|
||||
XMLFeature.prototype.readProjectionFromDocument = function(doc) {
|
||||
return this.dataProjection;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {Node} node Node.
|
||||
* @protected
|
||||
* @return {module:ol/proj/Projection} Projection.
|
||||
*/
|
||||
XMLFeature.prototype.readProjectionFromNode = function(node) {
|
||||
return this.dataProjection;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
XMLFeature.prototype.writeFeature = function(feature, opt_options) {
|
||||
const node = this.writeFeatureNode(feature, opt_options);
|
||||
return this.xmlSerializer_.serializeToString(node);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {module:ol/Feature} feature Feature.
|
||||
* @param {module:ol/format/Feature~WriteOptions=} opt_options Options.
|
||||
* @protected
|
||||
* @return {Node} Node.
|
||||
*/
|
||||
XMLFeature.prototype.writeFeatureNode = function(feature, opt_options) {
|
||||
return null; // not implemented
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
XMLFeature.prototype.writeFeatures = function(features, opt_options) {
|
||||
const node = this.writeFeaturesNode(features, opt_options);
|
||||
return this.xmlSerializer_.serializeToString(node);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {Array.<module:ol/Feature>} features Features.
|
||||
* @param {module:ol/format/Feature~WriteOptions=} opt_options Options.
|
||||
* @return {Node} Node.
|
||||
*/
|
||||
XMLFeature.prototype.writeFeaturesNode = function(features, opt_options) {
|
||||
return null; // not implemented
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
XMLFeature.prototype.writeGeometry = function(geometry, opt_options) {
|
||||
const node = this.writeGeometryNode(geometry, opt_options);
|
||||
return this.xmlSerializer_.serializeToString(node);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {module:ol/geom/Geometry} geometry Geometry.
|
||||
* @param {module:ol/format/Feature~WriteOptions=} opt_options Options.
|
||||
* @return {Node} Node.
|
||||
*/
|
||||
XMLFeature.prototype.writeGeometryNode = function(geometry, opt_options) {
|
||||
return null; // not implemented
|
||||
};
|
||||
export default XMLFeature;
|
||||
|
||||
@@ -1,23 +1,24 @@
|
||||
/**
|
||||
* @module ol/format/filter/And
|
||||
*/
|
||||
import {inherits} from '../../util.js';
|
||||
import LogicalNary from '../filter/LogicalNary.js';
|
||||
|
||||
/**
|
||||
* @classdesc
|
||||
* Represents a logical `<And>` operator between two or more filter conditions.
|
||||
*
|
||||
* @constructor
|
||||
* @abstract
|
||||
* @param {...module:ol/format/filter/Filter} conditions Conditions.
|
||||
* @extends {module:ol/format/filter/LogicalNary}
|
||||
*/
|
||||
const And = function(conditions) {
|
||||
const params = ['And'].concat(Array.prototype.slice.call(arguments));
|
||||
LogicalNary.apply(this, params);
|
||||
};
|
||||
class And extends LogicalNary {
|
||||
|
||||
inherits(And, LogicalNary);
|
||||
/**
|
||||
* @param {...module:ol/format/filter/Filter} conditions Conditions.
|
||||
*/
|
||||
constructor(conditions) {
|
||||
const params = ['And'].concat(Array.prototype.slice.call(arguments));
|
||||
super(...params);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default And;
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
/**
|
||||
* @module ol/format/filter/Bbox
|
||||
*/
|
||||
import {inherits} from '../../util.js';
|
||||
import Filter from '../filter/Filter.js';
|
||||
|
||||
/**
|
||||
@@ -9,34 +8,36 @@ import Filter from '../filter/Filter.js';
|
||||
* Represents a `<BBOX>` operator to test whether a geometry-valued property
|
||||
* intersects a fixed bounding box
|
||||
*
|
||||
* @constructor
|
||||
* @param {!string} geometryName Geometry name to use.
|
||||
* @param {!module:ol/extent~Extent} extent Extent.
|
||||
* @param {string=} opt_srsName SRS name. No srsName attribute will be
|
||||
* set on geometries when this is not provided.
|
||||
* @extends {module:ol/format/filter/Filter}
|
||||
* @api
|
||||
*/
|
||||
const Bbox = function(geometryName, extent, opt_srsName) {
|
||||
|
||||
Filter.call(this, 'BBOX');
|
||||
class Bbox extends Filter {
|
||||
|
||||
/**
|
||||
* @type {!string}
|
||||
* @param {!string} geometryName Geometry name to use.
|
||||
* @param {!module:ol/extent~Extent} extent Extent.
|
||||
* @param {string=} opt_srsName SRS name. No srsName attribute will be set
|
||||
* on geometries when this is not provided.
|
||||
*/
|
||||
this.geometryName = geometryName;
|
||||
constructor(geometryName, extent, opt_srsName) {
|
||||
|
||||
/**
|
||||
* @type {module:ol/extent~Extent}
|
||||
*/
|
||||
this.extent = extent;
|
||||
super('BBOX');
|
||||
|
||||
/**
|
||||
* @type {string|undefined}
|
||||
*/
|
||||
this.srsName = opt_srsName;
|
||||
};
|
||||
/**
|
||||
* @type {!string}
|
||||
*/
|
||||
this.geometryName = geometryName;
|
||||
|
||||
inherits(Bbox, Filter);
|
||||
/**
|
||||
* @type {module:ol/extent~Extent}
|
||||
*/
|
||||
this.extent = extent;
|
||||
|
||||
/**
|
||||
* @type {string|undefined}
|
||||
*/
|
||||
this.srsName = opt_srsName;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default Bbox;
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
/**
|
||||
* @module ol/format/filter/Comparison
|
||||
*/
|
||||
import {inherits} from '../../util.js';
|
||||
import Filter from '../filter/Filter.js';
|
||||
|
||||
/**
|
||||
@@ -9,22 +8,24 @@ import Filter from '../filter/Filter.js';
|
||||
* Abstract class; normally only used for creating subclasses and not instantiated in apps.
|
||||
* Base class for WFS GetFeature property comparison filters.
|
||||
*
|
||||
* @constructor
|
||||
* @abstract
|
||||
* @param {!string} tagName The XML tag name for this filter.
|
||||
* @param {!string} propertyName Name of the context property to compare.
|
||||
* @extends {module:ol/format/filter/Filter}
|
||||
*/
|
||||
const Comparison = function(tagName, propertyName) {
|
||||
|
||||
Filter.call(this, tagName);
|
||||
class Comparison extends Filter {
|
||||
|
||||
/**
|
||||
* @type {!string}
|
||||
* @param {!string} tagName The XML tag name for this filter.
|
||||
* @param {!string} propertyName Name of the context property to compare.
|
||||
*/
|
||||
this.propertyName = propertyName;
|
||||
};
|
||||
constructor(tagName, propertyName) {
|
||||
|
||||
inherits(Comparison, Filter);
|
||||
super(tagName);
|
||||
|
||||
/**
|
||||
* @type {!string}
|
||||
*/
|
||||
this.propertyName = propertyName;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default Comparison;
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
/**
|
||||
* @module ol/format/filter/ComparisonBinary
|
||||
*/
|
||||
import {inherits} from '../../util.js';
|
||||
import Comparison from '../filter/Comparison.js';
|
||||
|
||||
/**
|
||||
@@ -9,28 +8,31 @@ import Comparison from '../filter/Comparison.js';
|
||||
* Abstract class; normally only used for creating subclasses and not instantiated in apps.
|
||||
* Base class for WFS GetFeature property binary comparison filters.
|
||||
*
|
||||
* @constructor
|
||||
* @abstract
|
||||
* @param {!string} tagName The XML tag name for this filter.
|
||||
* @param {!string} propertyName Name of the context property to compare.
|
||||
* @param {!(string|number)} expression The value to compare.
|
||||
* @param {boolean=} opt_matchCase Case-sensitive?
|
||||
* @extends {module:ol/format/filter/Comparison}
|
||||
*/
|
||||
const ComparisonBinary = function(tagName, propertyName, expression, opt_matchCase) {
|
||||
|
||||
Comparison.call(this, tagName, propertyName);
|
||||
class ComparisonBinary extends Comparison {
|
||||
|
||||
/**
|
||||
* @type {!(string|number)}
|
||||
* @param {!string} tagName The XML tag name for this filter.
|
||||
* @param {!string} propertyName Name of the context property to compare.
|
||||
* @param {!(string|number)} expression The value to compare.
|
||||
* @param {boolean=} opt_matchCase Case-sensitive?
|
||||
*/
|
||||
this.expression = expression;
|
||||
constructor(tagName, propertyName, expression, opt_matchCase) {
|
||||
|
||||
/**
|
||||
* @type {boolean|undefined}
|
||||
*/
|
||||
this.matchCase = opt_matchCase;
|
||||
};
|
||||
super(tagName, propertyName);
|
||||
|
||||
/**
|
||||
* @type {!(string|number)}
|
||||
*/
|
||||
this.expression = expression;
|
||||
|
||||
/**
|
||||
* @type {boolean|undefined}
|
||||
*/
|
||||
this.matchCase = opt_matchCase;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
inherits(ComparisonBinary, Comparison);
|
||||
export default ComparisonBinary;
|
||||
|
||||
@@ -1,27 +1,28 @@
|
||||
/**
|
||||
* @module ol/format/filter/Contains
|
||||
*/
|
||||
import {inherits} from '../../util.js';
|
||||
import Spatial from '../filter/Spatial.js';
|
||||
|
||||
/**
|
||||
* @classdesc
|
||||
* Represents a `<Contains>` operator to test whether a geometry-valued property
|
||||
* contains a given geometry.
|
||||
*
|
||||
* @constructor
|
||||
* @param {!string} geometryName Geometry name to use.
|
||||
* @param {!module:ol/geom/Geometry} geometry Geometry.
|
||||
* @param {string=} opt_srsName SRS name. No srsName attribute will be
|
||||
* set on geometries when this is not provided.
|
||||
* @extends {module:ol/format/filter/Spatial}
|
||||
* @api
|
||||
*/
|
||||
const Contains = function(geometryName, geometry, opt_srsName) {
|
||||
class Contains extends Spatial {
|
||||
|
||||
Spatial.call(this, 'Contains', geometryName, geometry, opt_srsName);
|
||||
/**
|
||||
* @param {!string} geometryName Geometry name to use.
|
||||
* @param {!module:ol/geom/Geometry} geometry Geometry.
|
||||
* @param {string=} opt_srsName SRS name. No srsName attribute will be
|
||||
* set on geometries when this is not provided.
|
||||
* @api
|
||||
*/
|
||||
constructor(geometryName, geometry, opt_srsName) {
|
||||
|
||||
};
|
||||
super('Contains', geometryName, geometry, opt_srsName);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
inherits(Contains, Spatial);
|
||||
export default Contains;
|
||||
|
||||
@@ -1,33 +1,34 @@
|
||||
/**
|
||||
* @module ol/format/filter/During
|
||||
*/
|
||||
import {inherits} from '../../util.js';
|
||||
import Comparison from '../filter/Comparison.js';
|
||||
|
||||
/**
|
||||
* @classdesc
|
||||
* Represents a `<During>` comparison operator.
|
||||
*
|
||||
* @constructor
|
||||
* @param {!string} propertyName Name of the context property to compare.
|
||||
* @param {!string} begin The begin date in ISO-8601 format.
|
||||
* @param {!string} end The end date in ISO-8601 format.
|
||||
* @extends {module:ol/format/filter/Comparison}
|
||||
* @api
|
||||
*/
|
||||
const During = function(propertyName, begin, end) {
|
||||
Comparison.call(this, 'During', propertyName);
|
||||
class During extends Comparison {
|
||||
|
||||
/**
|
||||
* @type {!string}
|
||||
* @param {!string} propertyName Name of the context property to compare.
|
||||
* @param {!string} begin The begin date in ISO-8601 format.
|
||||
* @param {!string} end The end date in ISO-8601 format.
|
||||
* @api
|
||||
*/
|
||||
this.begin = begin;
|
||||
constructor(propertyName, begin, end) {
|
||||
super('During', propertyName);
|
||||
|
||||
/**
|
||||
* @type {!string}
|
||||
*/
|
||||
this.end = end;
|
||||
};
|
||||
/**
|
||||
* @type {!string}
|
||||
*/
|
||||
this.begin = begin;
|
||||
|
||||
/**
|
||||
* @type {!string}
|
||||
*/
|
||||
this.end = end;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
inherits(During, Comparison);
|
||||
export default During;
|
||||
|
||||
@@ -1,23 +1,24 @@
|
||||
/**
|
||||
* @module ol/format/filter/EqualTo
|
||||
*/
|
||||
import {inherits} from '../../util.js';
|
||||
import ComparisonBinary from '../filter/ComparisonBinary.js';
|
||||
|
||||
/**
|
||||
* @classdesc
|
||||
* Represents a `<PropertyIsEqualTo>` comparison operator.
|
||||
*
|
||||
* @constructor
|
||||
* @param {!string} propertyName Name of the context property to compare.
|
||||
* @param {!(string|number)} expression The value to compare.
|
||||
* @param {boolean=} opt_matchCase Case-sensitive?
|
||||
* @extends {module:ol/format/filter/ComparisonBinary}
|
||||
* @api
|
||||
*/
|
||||
const EqualTo = function(propertyName, expression, opt_matchCase) {
|
||||
ComparisonBinary.call(this, 'PropertyIsEqualTo', propertyName, expression, opt_matchCase);
|
||||
};
|
||||
class EqualTo extends ComparisonBinary {
|
||||
|
||||
/**
|
||||
* @param {!string} propertyName Name of the context property to compare.
|
||||
* @param {!(string|number)} expression The value to compare.
|
||||
* @param {boolean=} opt_matchCase Case-sensitive?
|
||||
* @api
|
||||
*/
|
||||
constructor(propertyName, expression, opt_matchCase) {
|
||||
super('PropertyIsEqualTo', propertyName, expression, opt_matchCase);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
inherits(EqualTo, ComparisonBinary);
|
||||
export default EqualTo;
|
||||
|
||||
@@ -8,26 +8,28 @@
|
||||
* Abstract class; normally only used for creating subclasses and not instantiated in apps.
|
||||
* Base class for WFS GetFeature filters.
|
||||
*
|
||||
* @constructor
|
||||
* @abstract
|
||||
* @param {!string} tagName The XML tag name for this filter.
|
||||
* @struct
|
||||
*/
|
||||
const Filter = function(tagName) {
|
||||
class Filter {
|
||||
/**
|
||||
* @param {!string} tagName The XML tag name for this filter.
|
||||
*/
|
||||
constructor(tagName) {
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {!string}
|
||||
*/
|
||||
this.tagName_ = tagName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {!string}
|
||||
* The XML tag name for a filter.
|
||||
* @returns {!string} Name.
|
||||
*/
|
||||
this.tagName_ = tagName;
|
||||
};
|
||||
|
||||
/**
|
||||
* The XML tag name for a filter.
|
||||
* @returns {!string} Name.
|
||||
*/
|
||||
Filter.prototype.getTagName = function() {
|
||||
return this.tagName_;
|
||||
};
|
||||
getTagName() {
|
||||
return this.tagName_;
|
||||
}
|
||||
}
|
||||
|
||||
export default Filter;
|
||||
|
||||
@@ -1,22 +1,23 @@
|
||||
/**
|
||||
* @module ol/format/filter/GreaterThan
|
||||
*/
|
||||
import {inherits} from '../../util.js';
|
||||
import ComparisonBinary from '../filter/ComparisonBinary.js';
|
||||
|
||||
/**
|
||||
* @classdesc
|
||||
* Represents a `<PropertyIsGreaterThan>` comparison operator.
|
||||
*
|
||||
* @constructor
|
||||
* @param {!string} propertyName Name of the context property to compare.
|
||||
* @param {!number} expression The value to compare.
|
||||
* @extends {module:ol/format/filter/ComparisonBinary}
|
||||
* @api
|
||||
*/
|
||||
const GreaterThan = function(propertyName, expression) {
|
||||
ComparisonBinary.call(this, 'PropertyIsGreaterThan', propertyName, expression);
|
||||
};
|
||||
class GreaterThan extends ComparisonBinary {
|
||||
|
||||
/**
|
||||
* @param {!string} propertyName Name of the context property to compare.
|
||||
* @param {!number} expression The value to compare.
|
||||
* @api
|
||||
*/
|
||||
constructor(propertyName, expression) {
|
||||
super('PropertyIsGreaterThan', propertyName, expression);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
inherits(GreaterThan, ComparisonBinary);
|
||||
export default GreaterThan;
|
||||
|
||||
@@ -1,22 +1,23 @@
|
||||
/**
|
||||
* @module ol/format/filter/GreaterThanOrEqualTo
|
||||
*/
|
||||
import {inherits} from '../../util.js';
|
||||
import ComparisonBinary from '../filter/ComparisonBinary.js';
|
||||
|
||||
/**
|
||||
* @classdesc
|
||||
* Represents a `<PropertyIsGreaterThanOrEqualTo>` comparison operator.
|
||||
*
|
||||
* @constructor
|
||||
* @param {!string} propertyName Name of the context property to compare.
|
||||
* @param {!number} expression The value to compare.
|
||||
* @extends {module:ol/format/filter/ComparisonBinary}
|
||||
* @api
|
||||
*/
|
||||
const GreaterThanOrEqualTo = function(propertyName, expression) {
|
||||
ComparisonBinary.call(this, 'PropertyIsGreaterThanOrEqualTo', propertyName, expression);
|
||||
};
|
||||
class GreaterThanOrEqualTo extends ComparisonBinary {
|
||||
|
||||
/**
|
||||
* @param {!string} propertyName Name of the context property to compare.
|
||||
* @param {!number} expression The value to compare.
|
||||
* @api
|
||||
*/
|
||||
constructor(propertyName, expression) {
|
||||
super('PropertyIsGreaterThanOrEqualTo', propertyName, expression);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
inherits(GreaterThanOrEqualTo, ComparisonBinary);
|
||||
export default GreaterThanOrEqualTo;
|
||||
|
||||
@@ -1,27 +1,25 @@
|
||||
/**
|
||||
* @module ol/format/filter/Intersects
|
||||
*/
|
||||
import {inherits} from '../../util.js';
|
||||
import Spatial from '../filter/Spatial.js';
|
||||
|
||||
/**
|
||||
* @classdesc
|
||||
* Represents a `<Intersects>` operator to test whether a geometry-valued property
|
||||
* intersects a given geometry.
|
||||
*
|
||||
* @constructor
|
||||
* @param {!string} geometryName Geometry name to use.
|
||||
* @param {!module:ol/geom/Geometry} geometry Geometry.
|
||||
* @param {string=} opt_srsName SRS name. No srsName attribute will be
|
||||
* set on geometries when this is not provided.
|
||||
* @extends {module:ol/format/filter/Spatial}
|
||||
* @api
|
||||
*/
|
||||
const Intersects = function(geometryName, geometry, opt_srsName) {
|
||||
class Intersects extends Spatial {
|
||||
|
||||
Spatial.call(this, 'Intersects', geometryName, geometry, opt_srsName);
|
||||
/**
|
||||
* @param {!string} geometryName Geometry name to use.
|
||||
* @param {!module:ol/geom/Geometry} geometry Geometry.
|
||||
* @param {string=} opt_srsName SRS name. No srsName attribute will be
|
||||
* set on geometries when this is not provided.
|
||||
*/
|
||||
constructor(geometryName, geometry, opt_srsName) {
|
||||
super('Intersects', geometryName, geometry, opt_srsName);
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
inherits(Intersects, Spatial);
|
||||
export default Intersects;
|
||||
|
||||
@@ -1,33 +1,34 @@
|
||||
/**
|
||||
* @module ol/format/filter/IsBetween
|
||||
*/
|
||||
import {inherits} from '../../util.js';
|
||||
import Comparison from '../filter/Comparison.js';
|
||||
|
||||
/**
|
||||
* @classdesc
|
||||
* Represents a `<PropertyIsBetween>` comparison operator.
|
||||
*
|
||||
* @constructor
|
||||
* @param {!string} propertyName Name of the context property to compare.
|
||||
* @param {!number} lowerBoundary The lower bound of the range.
|
||||
* @param {!number} upperBoundary The upper bound of the range.
|
||||
* @extends {module:ol/format/filter/Comparison}
|
||||
* @api
|
||||
*/
|
||||
const IsBetween = function(propertyName, lowerBoundary, upperBoundary) {
|
||||
Comparison.call(this, 'PropertyIsBetween', propertyName);
|
||||
class IsBetween extends Comparison {
|
||||
|
||||
/**
|
||||
* @type {!number}
|
||||
* @param {!string} propertyName Name of the context property to compare.
|
||||
* @param {!number} lowerBoundary The lower bound of the range.
|
||||
* @param {!number} upperBoundary The upper bound of the range.
|
||||
* @api
|
||||
*/
|
||||
this.lowerBoundary = lowerBoundary;
|
||||
constructor(propertyName, lowerBoundary, upperBoundary) {
|
||||
super('PropertyIsBetween', propertyName);
|
||||
|
||||
/**
|
||||
* @type {!number}
|
||||
*/
|
||||
this.upperBoundary = upperBoundary;
|
||||
};
|
||||
/**
|
||||
* @type {!number}
|
||||
*/
|
||||
this.lowerBoundary = lowerBoundary;
|
||||
|
||||
/**
|
||||
* @type {!number}
|
||||
*/
|
||||
this.upperBoundary = upperBoundary;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
inherits(IsBetween, Comparison);
|
||||
export default IsBetween;
|
||||
|
||||
@@ -1,54 +1,56 @@
|
||||
/**
|
||||
* @module ol/format/filter/IsLike
|
||||
*/
|
||||
import {inherits} from '../../util.js';
|
||||
import Comparison from '../filter/Comparison.js';
|
||||
|
||||
/**
|
||||
* @classdesc
|
||||
* Represents a `<PropertyIsLike>` comparison operator.
|
||||
*
|
||||
* @constructor
|
||||
* @param {!string} propertyName Name of the context property to compare.
|
||||
* @param {!string} pattern Text pattern.
|
||||
* @param {string=} opt_wildCard Pattern character which matches any sequence of
|
||||
* zero or more string characters. Default is '*'.
|
||||
* @param {string=} opt_singleChar pattern character which matches any single
|
||||
* string character. Default is '.'.
|
||||
* @param {string=} opt_escapeChar Escape character which can be used to escape
|
||||
* the pattern characters. Default is '!'.
|
||||
* @param {boolean=} opt_matchCase Case-sensitive?
|
||||
* @extends {module:ol/format/filter/Comparison}
|
||||
* @api
|
||||
*/
|
||||
const IsLike = function(propertyName, pattern, opt_wildCard, opt_singleChar, opt_escapeChar, opt_matchCase) {
|
||||
Comparison.call(this, 'PropertyIsLike', propertyName);
|
||||
class IsLike extends Comparison {
|
||||
|
||||
/**
|
||||
* @type {!string}
|
||||
* [constructor description]
|
||||
* @param {!string} propertyName Name of the context property to compare.
|
||||
* @param {!string} pattern Text pattern.
|
||||
* @param {string=} opt_wildCard Pattern character which matches any sequence of
|
||||
* zero or more string characters. Default is '*'.
|
||||
* @param {string=} opt_singleChar pattern character which matches any single
|
||||
* string character. Default is '.'.
|
||||
* @param {string=} opt_escapeChar Escape character which can be used to escape
|
||||
* the pattern characters. Default is '!'.
|
||||
* @param {boolean=} opt_matchCase Case-sensitive?
|
||||
* @api
|
||||
*/
|
||||
this.pattern = pattern;
|
||||
constructor(propertyName, pattern, opt_wildCard, opt_singleChar, opt_escapeChar, opt_matchCase) {
|
||||
super('PropertyIsLike', propertyName);
|
||||
|
||||
/**
|
||||
* @type {!string}
|
||||
*/
|
||||
this.wildCard = (opt_wildCard !== undefined) ? opt_wildCard : '*';
|
||||
/**
|
||||
* @type {!string}
|
||||
*/
|
||||
this.pattern = pattern;
|
||||
|
||||
/**
|
||||
* @type {!string}
|
||||
*/
|
||||
this.singleChar = (opt_singleChar !== undefined) ? opt_singleChar : '.';
|
||||
/**
|
||||
* @type {!string}
|
||||
*/
|
||||
this.wildCard = (opt_wildCard !== undefined) ? opt_wildCard : '*';
|
||||
|
||||
/**
|
||||
* @type {!string}
|
||||
*/
|
||||
this.escapeChar = (opt_escapeChar !== undefined) ? opt_escapeChar : '!';
|
||||
/**
|
||||
* @type {!string}
|
||||
*/
|
||||
this.singleChar = (opt_singleChar !== undefined) ? opt_singleChar : '.';
|
||||
|
||||
/**
|
||||
* @type {boolean|undefined}
|
||||
*/
|
||||
this.matchCase = opt_matchCase;
|
||||
};
|
||||
/**
|
||||
* @type {!string}
|
||||
*/
|
||||
this.escapeChar = (opt_escapeChar !== undefined) ? opt_escapeChar : '!';
|
||||
|
||||
/**
|
||||
* @type {boolean|undefined}
|
||||
*/
|
||||
this.matchCase = opt_matchCase;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
inherits(IsLike, Comparison);
|
||||
export default IsLike;
|
||||
|
||||
@@ -1,21 +1,22 @@
|
||||
/**
|
||||
* @module ol/format/filter/IsNull
|
||||
*/
|
||||
import {inherits} from '../../util.js';
|
||||
import Comparison from '../filter/Comparison.js';
|
||||
|
||||
/**
|
||||
* @classdesc
|
||||
* Represents a `<PropertyIsNull>` comparison operator.
|
||||
*
|
||||
* @constructor
|
||||
* @param {!string} propertyName Name of the context property to compare.
|
||||
* @extends {module:ol/format/filter/Comparison}
|
||||
* @api
|
||||
*/
|
||||
const IsNull = function(propertyName) {
|
||||
Comparison.call(this, 'PropertyIsNull', propertyName);
|
||||
};
|
||||
class IsNull extends Comparison {
|
||||
|
||||
/**
|
||||
* @param {!string} propertyName Name of the context property to compare.
|
||||
* @api
|
||||
*/
|
||||
constructor(propertyName) {
|
||||
super('PropertyIsNull', propertyName);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
inherits(IsNull, Comparison);
|
||||
export default IsNull;
|
||||
|
||||
@@ -1,22 +1,23 @@
|
||||
/**
|
||||
* @module ol/format/filter/LessThan
|
||||
*/
|
||||
import {inherits} from '../../util.js';
|
||||
import ComparisonBinary from '../filter/ComparisonBinary.js';
|
||||
|
||||
/**
|
||||
* @classdesc
|
||||
* Represents a `<PropertyIsLessThan>` comparison operator.
|
||||
*
|
||||
* @constructor
|
||||
* @param {!string} propertyName Name of the context property to compare.
|
||||
* @param {!number} expression The value to compare.
|
||||
* @extends {module:ol/format/filter/ComparisonBinary}
|
||||
* @api
|
||||
*/
|
||||
const LessThan = function(propertyName, expression) {
|
||||
ComparisonBinary.call(this, 'PropertyIsLessThan', propertyName, expression);
|
||||
};
|
||||
class LessThan extends ComparisonBinary {
|
||||
|
||||
/**
|
||||
* @param {!string} propertyName Name of the context property to compare.
|
||||
* @param {!number} expression The value to compare.
|
||||
* @api
|
||||
*/
|
||||
constructor(propertyName, expression) {
|
||||
super('PropertyIsLessThan', propertyName, expression);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
inherits(LessThan, ComparisonBinary);
|
||||
export default LessThan;
|
||||
|
||||
@@ -1,22 +1,23 @@
|
||||
/**
|
||||
* @module ol/format/filter/LessThanOrEqualTo
|
||||
*/
|
||||
import {inherits} from '../../util.js';
|
||||
import ComparisonBinary from '../filter/ComparisonBinary.js';
|
||||
|
||||
/**
|
||||
* @classdesc
|
||||
* Represents a `<PropertyIsLessThanOrEqualTo>` comparison operator.
|
||||
*
|
||||
* @constructor
|
||||
* @param {!string} propertyName Name of the context property to compare.
|
||||
* @param {!number} expression The value to compare.
|
||||
* @extends {module:ol/format/filter/ComparisonBinary}
|
||||
* @api
|
||||
*/
|
||||
const LessThanOrEqualTo = function(propertyName, expression) {
|
||||
ComparisonBinary.call(this, 'PropertyIsLessThanOrEqualTo', propertyName, expression);
|
||||
};
|
||||
class LessThanOrEqualTo extends ComparisonBinary {
|
||||
|
||||
/**
|
||||
* @param {!string} propertyName Name of the context property to compare.
|
||||
* @param {!number} expression The value to compare.
|
||||
* @api
|
||||
*/
|
||||
constructor(propertyName, expression) {
|
||||
super('PropertyIsLessThanOrEqualTo', propertyName, expression);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
inherits(LessThanOrEqualTo, ComparisonBinary);
|
||||
export default LessThanOrEqualTo;
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
/**
|
||||
* @module ol/format/filter/LogicalNary
|
||||
*/
|
||||
import {inherits} from '../../util.js';
|
||||
import {assert} from '../../asserts.js';
|
||||
import Filter from '../filter/Filter.js';
|
||||
|
||||
@@ -10,22 +9,25 @@ import Filter from '../filter/Filter.js';
|
||||
* Abstract class; normally only used for creating subclasses and not instantiated in apps.
|
||||
* Base class for WFS GetFeature n-ary logical filters.
|
||||
*
|
||||
* @constructor
|
||||
* @abstract
|
||||
* @param {!string} tagName The XML tag name for this filter.
|
||||
* @param {...module:ol/format/filter/Filter} conditions Conditions.
|
||||
* @extends {module:ol/format/filter/Filter}
|
||||
*/
|
||||
const LogicalNary = function(tagName, conditions) {
|
||||
|
||||
Filter.call(this, tagName);
|
||||
class LogicalNary extends Filter {
|
||||
|
||||
/**
|
||||
* @type {Array.<module:ol/format/filter/Filter>}
|
||||
* @param {!string} tagName The XML tag name for this filter.
|
||||
* @param {...module:ol/format/filter/Filter} conditions Conditions.
|
||||
*/
|
||||
this.conditions = Array.prototype.slice.call(arguments, 1);
|
||||
assert(this.conditions.length >= 2, 57); // At least 2 conditions are required.
|
||||
};
|
||||
constructor(tagName, conditions) {
|
||||
|
||||
super(tagName);
|
||||
|
||||
/**
|
||||
* @type {Array.<module:ol/format/filter/Filter>}
|
||||
*/
|
||||
this.conditions = Array.prototype.slice.call(arguments, 1);
|
||||
assert(this.conditions.length >= 2, 57); // At least 2 conditions are required.
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
inherits(LogicalNary, Filter);
|
||||
export default LogicalNary;
|
||||
|
||||
@@ -1,27 +1,29 @@
|
||||
/**
|
||||
* @module ol/format/filter/Not
|
||||
*/
|
||||
import {inherits} from '../../util.js';
|
||||
import Filter from '../filter/Filter.js';
|
||||
|
||||
/**
|
||||
* @classdesc
|
||||
* Represents a logical `<Not>` operator for a filter condition.
|
||||
*
|
||||
* @constructor
|
||||
* @param {!module:ol/format/filter/Filter} condition Filter condition.
|
||||
* @extends {module:ol/format/filter/Filter}
|
||||
* @api
|
||||
*/
|
||||
const Not = function(condition) {
|
||||
|
||||
Filter.call(this, 'Not');
|
||||
class Not extends Filter {
|
||||
|
||||
/**
|
||||
* @type {!module:ol/format/filter/Filter}
|
||||
* @param {!module:ol/format/filter/Filter} condition Filter condition.
|
||||
* @api
|
||||
*/
|
||||
this.condition = condition;
|
||||
};
|
||||
constructor(condition) {
|
||||
|
||||
super('Not');
|
||||
|
||||
/**
|
||||
* @type {!module:ol/format/filter/Filter}
|
||||
*/
|
||||
this.condition = condition;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
inherits(Not, Filter);
|
||||
export default Not;
|
||||
|
||||
@@ -1,23 +1,24 @@
|
||||
/**
|
||||
* @module ol/format/filter/NotEqualTo
|
||||
*/
|
||||
import {inherits} from '../../util.js';
|
||||
import ComparisonBinary from '../filter/ComparisonBinary.js';
|
||||
|
||||
/**
|
||||
* @classdesc
|
||||
* Represents a `<PropertyIsNotEqualTo>` comparison operator.
|
||||
*
|
||||
* @constructor
|
||||
* @param {!string} propertyName Name of the context property to compare.
|
||||
* @param {!(string|number)} expression The value to compare.
|
||||
* @param {boolean=} opt_matchCase Case-sensitive?
|
||||
* @extends {module:ol/format/filter/ComparisonBinary}
|
||||
* @api
|
||||
*/
|
||||
const NotEqualTo = function(propertyName, expression, opt_matchCase) {
|
||||
ComparisonBinary.call(this, 'PropertyIsNotEqualTo', propertyName, expression, opt_matchCase);
|
||||
};
|
||||
class NotEqualTo extends ComparisonBinary {
|
||||
|
||||
/**
|
||||
* @param {!string} propertyName Name of the context property to compare.
|
||||
* @param {!(string|number)} expression The value to compare.
|
||||
* @param {boolean=} opt_matchCase Case-sensitive?
|
||||
* @api
|
||||
*/
|
||||
constructor(propertyName, expression, opt_matchCase) {
|
||||
super('PropertyIsNotEqualTo', propertyName, expression, opt_matchCase);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
inherits(NotEqualTo, ComparisonBinary);
|
||||
export default NotEqualTo;
|
||||
|
||||
@@ -1,22 +1,23 @@
|
||||
/**
|
||||
* @module ol/format/filter/Or
|
||||
*/
|
||||
import {inherits} from '../../util.js';
|
||||
import LogicalNary from '../filter/LogicalNary.js';
|
||||
|
||||
/**
|
||||
* @classdesc
|
||||
* Represents a logical `<Or>` operator between two ore more filter conditions.
|
||||
*
|
||||
* @constructor
|
||||
* @param {...module:ol/format/filter/Filter} conditions Conditions.
|
||||
* @extends {module:ol/format/filter/LogicalNary}
|
||||
* @api
|
||||
*/
|
||||
const Or = function(conditions) {
|
||||
const params = ['Or'].concat(Array.prototype.slice.call(arguments));
|
||||
LogicalNary.apply(this, params);
|
||||
};
|
||||
class Or extends LogicalNary {
|
||||
|
||||
/**
|
||||
* @param {...module:ol/format/filter/Filter} conditions Conditions.
|
||||
* @api
|
||||
*/
|
||||
constructor(conditions) {
|
||||
const params = ['Or'].concat(Array.prototype.slice.call(arguments));
|
||||
super(...params);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
inherits(Or, LogicalNary);
|
||||
export default Or;
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
/**
|
||||
* @module ol/format/filter/Spatial
|
||||
*/
|
||||
import {inherits} from '../../util.js';
|
||||
import Filter from '../filter/Filter.js';
|
||||
|
||||
/**
|
||||
@@ -10,35 +9,37 @@ import Filter from '../filter/Filter.js';
|
||||
* Represents a spatial operator to test whether a geometry-valued property
|
||||
* relates to a given geometry.
|
||||
*
|
||||
* @constructor
|
||||
* @abstract
|
||||
* @param {!string} tagName The XML tag name for this filter.
|
||||
* @param {!string} geometryName Geometry name to use.
|
||||
* @param {!module:ol/geom/Geometry} geometry Geometry.
|
||||
* @param {string=} opt_srsName SRS name. No srsName attribute will be
|
||||
* set on geometries when this is not provided.
|
||||
* @extends {module:ol/format/filter/Filter}
|
||||
*/
|
||||
const Spatial = function(tagName, geometryName, geometry, opt_srsName) {
|
||||
|
||||
Filter.call(this, tagName);
|
||||
class Spatial extends Filter {
|
||||
|
||||
/**
|
||||
* @type {!string}
|
||||
* @param {!string} tagName The XML tag name for this filter.
|
||||
* @param {!string} geometryName Geometry name to use.
|
||||
* @param {!module:ol/geom/Geometry} geometry Geometry.
|
||||
* @param {string=} opt_srsName SRS name. No srsName attribute will be
|
||||
* set on geometries when this is not provided.
|
||||
*/
|
||||
this.geometryName = geometryName || 'the_geom';
|
||||
constructor(tagName, geometryName, geometry, opt_srsName) {
|
||||
|
||||
/**
|
||||
* @type {module:ol/geom/Geometry}
|
||||
*/
|
||||
this.geometry = geometry;
|
||||
super(tagName);
|
||||
|
||||
/**
|
||||
* @type {string|undefined}
|
||||
*/
|
||||
this.srsName = opt_srsName;
|
||||
};
|
||||
/**
|
||||
* @type {!string}
|
||||
*/
|
||||
this.geometryName = geometryName || 'the_geom';
|
||||
|
||||
inherits(Spatial, Filter);
|
||||
/**
|
||||
* @type {module:ol/geom/Geometry}
|
||||
*/
|
||||
this.geometry = geometry;
|
||||
|
||||
/**
|
||||
* @type {string|undefined}
|
||||
*/
|
||||
this.srsName = opt_srsName;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default Spatial;
|
||||
|
||||
@@ -1,27 +1,26 @@
|
||||
/**
|
||||
* @module ol/format/filter/Within
|
||||
*/
|
||||
import {inherits} from '../../util.js';
|
||||
import Spatial from '../filter/Spatial.js';
|
||||
|
||||
/**
|
||||
* @classdesc
|
||||
* Represents a `<Within>` operator to test whether a geometry-valued property
|
||||
* is within a given geometry.
|
||||
*
|
||||
* @constructor
|
||||
* @param {!string} geometryName Geometry name to use.
|
||||
* @param {!module:ol/geom/Geometry} geometry Geometry.
|
||||
* @param {string=} opt_srsName SRS name. No srsName attribute will be
|
||||
* set on geometries when this is not provided.
|
||||
* @extends {module:ol/format/filter/Spatial}
|
||||
* @api
|
||||
*/
|
||||
const Within = function(geometryName, geometry, opt_srsName) {
|
||||
class Within extends Spatial {
|
||||
|
||||
Spatial.call(this, 'Within', geometryName, geometry, opt_srsName);
|
||||
/**
|
||||
* @param {!string} geometryName Geometry name to use.
|
||||
* @param {!module:ol/geom/Geometry} geometry Geometry.
|
||||
* @param {string=} opt_srsName SRS name. No srsName attribute will be
|
||||
* set on geometries when this is not provided.
|
||||
* @api
|
||||
*/
|
||||
constructor(geometryName, geometry, opt_srsName) {
|
||||
super('Within', geometryName, geometry, opt_srsName);
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
inherits(Within, Spatial);
|
||||
export default Within;
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
/**
|
||||
* @module ol/geom/Circle
|
||||
*/
|
||||
import {inherits} from '../util.js';
|
||||
import {createOrUpdate, forEachCorner, intersects} from '../extent.js';
|
||||
import GeometryType from '../geom/GeometryType.js';
|
||||
import SimpleGeometry from '../geom/SimpleGeometry.js';
|
||||
@@ -11,220 +10,207 @@ import {deflateCoordinate} from '../geom/flat/deflate.js';
|
||||
* @classdesc
|
||||
* Circle geometry.
|
||||
*
|
||||
* @constructor
|
||||
* @extends {!module:ol/geom/SimpleGeometry}
|
||||
* @param {!module:ol/coordinate~Coordinate} center Center. (For internal use,
|
||||
* flat coordinates in combination with `opt_layout` and no `opt_radius` are
|
||||
* also accepted.)
|
||||
* @param {number=} opt_radius Radius.
|
||||
* @param {module:ol/geom/GeometryLayout=} opt_layout Layout.
|
||||
* @api
|
||||
*/
|
||||
const Circle = function(center, opt_radius, opt_layout) {
|
||||
SimpleGeometry.call(this);
|
||||
if (opt_layout !== undefined && opt_radius === undefined) {
|
||||
this.setFlatCoordinates(opt_layout, center);
|
||||
} else {
|
||||
const radius = opt_radius ? opt_radius : 0;
|
||||
this.setCenterAndRadius(center, radius, opt_layout);
|
||||
}
|
||||
};
|
||||
class Circle extends SimpleGeometry {
|
||||
|
||||
inherits(Circle, SimpleGeometry);
|
||||
|
||||
|
||||
/**
|
||||
* Make a complete copy of the geometry.
|
||||
* @return {!module:ol/geom/Circle} Clone.
|
||||
* @override
|
||||
* @api
|
||||
*/
|
||||
Circle.prototype.clone = function() {
|
||||
return new Circle(this.flatCoordinates.slice(), undefined, this.layout);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
Circle.prototype.closestPointXY = function(x, y, closestPoint, minSquaredDistance) {
|
||||
const flatCoordinates = this.flatCoordinates;
|
||||
const dx = x - flatCoordinates[0];
|
||||
const dy = y - flatCoordinates[1];
|
||||
const squaredDistance = dx * dx + dy * dy;
|
||||
if (squaredDistance < minSquaredDistance) {
|
||||
if (squaredDistance === 0) {
|
||||
for (let i = 0; i < this.stride; ++i) {
|
||||
closestPoint[i] = flatCoordinates[i];
|
||||
}
|
||||
/**
|
||||
* @param {!module:ol/coordinate~Coordinate} center Center.
|
||||
* For internal use, flat coordinates in combination with `opt_layout` and no
|
||||
* `opt_radius` are also accepted.
|
||||
* @param {number=} opt_radius Radius.
|
||||
* @param {module:ol/geom/GeometryLayout=} opt_layout Layout.
|
||||
*/
|
||||
constructor(center, opt_radius, opt_layout) {
|
||||
super();
|
||||
if (opt_layout !== undefined && opt_radius === undefined) {
|
||||
this.setFlatCoordinates(opt_layout, center);
|
||||
} else {
|
||||
const delta = this.getRadius() / Math.sqrt(squaredDistance);
|
||||
closestPoint[0] = flatCoordinates[0] + delta * dx;
|
||||
closestPoint[1] = flatCoordinates[1] + delta * dy;
|
||||
for (let i = 2; i < this.stride; ++i) {
|
||||
closestPoint[i] = flatCoordinates[i];
|
||||
const radius = opt_radius ? opt_radius : 0;
|
||||
this.setCenterAndRadius(center, radius, opt_layout);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Make a complete copy of the geometry.
|
||||
* @return {!module:ol/geom/Circle} Clone.
|
||||
* @override
|
||||
* @api
|
||||
*/
|
||||
clone() {
|
||||
return new Circle(this.flatCoordinates.slice(), undefined, this.layout);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
closestPointXY(x, y, closestPoint, minSquaredDistance) {
|
||||
const flatCoordinates = this.flatCoordinates;
|
||||
const dx = x - flatCoordinates[0];
|
||||
const dy = y - flatCoordinates[1];
|
||||
const squaredDistance = dx * dx + dy * dy;
|
||||
if (squaredDistance < minSquaredDistance) {
|
||||
if (squaredDistance === 0) {
|
||||
for (let i = 0; i < this.stride; ++i) {
|
||||
closestPoint[i] = flatCoordinates[i];
|
||||
}
|
||||
} else {
|
||||
const delta = this.getRadius() / Math.sqrt(squaredDistance);
|
||||
closestPoint[0] = flatCoordinates[0] + delta * dx;
|
||||
closestPoint[1] = flatCoordinates[1] + delta * dy;
|
||||
for (let i = 2; i < this.stride; ++i) {
|
||||
closestPoint[i] = flatCoordinates[i];
|
||||
}
|
||||
}
|
||||
closestPoint.length = this.stride;
|
||||
return squaredDistance;
|
||||
} else {
|
||||
return minSquaredDistance;
|
||||
}
|
||||
closestPoint.length = this.stride;
|
||||
return squaredDistance;
|
||||
} else {
|
||||
return minSquaredDistance;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
containsXY(x, y) {
|
||||
const flatCoordinates = this.flatCoordinates;
|
||||
const dx = x - flatCoordinates[0];
|
||||
const dy = y - flatCoordinates[1];
|
||||
return dx * dx + dy * dy <= this.getRadiusSquared_();
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
Circle.prototype.containsXY = function(x, y) {
|
||||
const flatCoordinates = this.flatCoordinates;
|
||||
const dx = x - flatCoordinates[0];
|
||||
const dy = y - flatCoordinates[1];
|
||||
return dx * dx + dy * dy <= this.getRadiusSquared_();
|
||||
};
|
||||
/**
|
||||
* Return the center of the circle as {@link module:ol/coordinate~Coordinate coordinate}.
|
||||
* @return {module:ol/coordinate~Coordinate} Center.
|
||||
* @api
|
||||
*/
|
||||
getCenter() {
|
||||
return this.flatCoordinates.slice(0, this.stride);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
computeExtent(extent) {
|
||||
const flatCoordinates = this.flatCoordinates;
|
||||
const radius = flatCoordinates[this.stride] - flatCoordinates[0];
|
||||
return createOrUpdate(
|
||||
flatCoordinates[0] - radius, flatCoordinates[1] - radius,
|
||||
flatCoordinates[0] + radius, flatCoordinates[1] + radius,
|
||||
extent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the center of the circle as {@link module:ol/coordinate~Coordinate coordinate}.
|
||||
* @return {module:ol/coordinate~Coordinate} Center.
|
||||
* @api
|
||||
*/
|
||||
Circle.prototype.getCenter = function() {
|
||||
return this.flatCoordinates.slice(0, this.stride);
|
||||
};
|
||||
/**
|
||||
* Return the radius of the circle.
|
||||
* @return {number} Radius.
|
||||
* @api
|
||||
*/
|
||||
getRadius() {
|
||||
return Math.sqrt(this.getRadiusSquared_());
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @return {number} Radius squared.
|
||||
*/
|
||||
getRadiusSquared_() {
|
||||
const dx = this.flatCoordinates[this.stride] - this.flatCoordinates[0];
|
||||
const dy = this.flatCoordinates[this.stride + 1] - this.flatCoordinates[1];
|
||||
return dx * dx + dy * dy;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
Circle.prototype.computeExtent = function(extent) {
|
||||
const flatCoordinates = this.flatCoordinates;
|
||||
const radius = flatCoordinates[this.stride] - flatCoordinates[0];
|
||||
return createOrUpdate(
|
||||
flatCoordinates[0] - radius, flatCoordinates[1] - radius,
|
||||
flatCoordinates[0] + radius, flatCoordinates[1] + radius,
|
||||
extent);
|
||||
};
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @api
|
||||
*/
|
||||
getType() {
|
||||
return GeometryType.CIRCLE;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @api
|
||||
*/
|
||||
intersectsExtent(extent) {
|
||||
const circleExtent = this.getExtent();
|
||||
if (intersects(extent, circleExtent)) {
|
||||
const center = this.getCenter();
|
||||
|
||||
/**
|
||||
* Return the radius of the circle.
|
||||
* @return {number} Radius.
|
||||
* @api
|
||||
*/
|
||||
Circle.prototype.getRadius = function() {
|
||||
return Math.sqrt(this.getRadiusSquared_());
|
||||
};
|
||||
if (extent[0] <= center[0] && extent[2] >= center[0]) {
|
||||
return true;
|
||||
}
|
||||
if (extent[1] <= center[1] && extent[3] >= center[1]) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @return {number} Radius squared.
|
||||
*/
|
||||
Circle.prototype.getRadiusSquared_ = function() {
|
||||
const dx = this.flatCoordinates[this.stride] - this.flatCoordinates[0];
|
||||
const dy = this.flatCoordinates[this.stride + 1] - this.flatCoordinates[1];
|
||||
return dx * dx + dy * dy;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @api
|
||||
*/
|
||||
Circle.prototype.getType = function() {
|
||||
return GeometryType.CIRCLE;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @api
|
||||
*/
|
||||
Circle.prototype.intersectsExtent = function(extent) {
|
||||
const circleExtent = this.getExtent();
|
||||
if (intersects(extent, circleExtent)) {
|
||||
const center = this.getCenter();
|
||||
|
||||
if (extent[0] <= center[0] && extent[2] >= center[0]) {
|
||||
return true;
|
||||
return forEachCorner(extent, this.intersectsCoordinate, this);
|
||||
}
|
||||
if (extent[1] <= center[1] && extent[3] >= center[1]) {
|
||||
return true;
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the center of the circle as {@link module:ol/coordinate~Coordinate coordinate}.
|
||||
* @param {module:ol/coordinate~Coordinate} center Center.
|
||||
* @api
|
||||
*/
|
||||
setCenter(center) {
|
||||
const stride = this.stride;
|
||||
const radius = this.flatCoordinates[stride] - this.flatCoordinates[0];
|
||||
const flatCoordinates = center.slice();
|
||||
flatCoordinates[stride] = flatCoordinates[0] + radius;
|
||||
for (let i = 1; i < stride; ++i) {
|
||||
flatCoordinates[stride + i] = center[i];
|
||||
}
|
||||
|
||||
return forEachCorner(extent, this.intersectsCoordinate, this);
|
||||
this.setFlatCoordinates(this.layout, flatCoordinates);
|
||||
this.changed();
|
||||
}
|
||||
return false;
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Set the center of the circle as {@link module:ol/coordinate~Coordinate coordinate}.
|
||||
* @param {module:ol/coordinate~Coordinate} center Center.
|
||||
* @api
|
||||
*/
|
||||
Circle.prototype.setCenter = function(center) {
|
||||
const stride = this.stride;
|
||||
const radius = this.flatCoordinates[stride] - this.flatCoordinates[0];
|
||||
const flatCoordinates = center.slice();
|
||||
flatCoordinates[stride] = flatCoordinates[0] + radius;
|
||||
for (let i = 1; i < stride; ++i) {
|
||||
flatCoordinates[stride + i] = center[i];
|
||||
/**
|
||||
* Set the center (as {@link module:ol/coordinate~Coordinate coordinate}) and the radius (as
|
||||
* number) of the circle.
|
||||
* @param {!module:ol/coordinate~Coordinate} center Center.
|
||||
* @param {number} radius Radius.
|
||||
* @param {module:ol/geom/GeometryLayout=} opt_layout Layout.
|
||||
* @api
|
||||
*/
|
||||
setCenterAndRadius(center, radius, opt_layout) {
|
||||
this.setLayout(opt_layout, center, 0);
|
||||
if (!this.flatCoordinates) {
|
||||
this.flatCoordinates = [];
|
||||
}
|
||||
/** @type {Array.<number>} */
|
||||
const flatCoordinates = this.flatCoordinates;
|
||||
let offset = deflateCoordinate(
|
||||
flatCoordinates, 0, center, this.stride);
|
||||
flatCoordinates[offset++] = flatCoordinates[0] + radius;
|
||||
for (let i = 1, ii = this.stride; i < ii; ++i) {
|
||||
flatCoordinates[offset++] = flatCoordinates[i];
|
||||
}
|
||||
flatCoordinates.length = offset;
|
||||
this.changed();
|
||||
}
|
||||
this.setFlatCoordinates(this.layout, flatCoordinates);
|
||||
this.changed();
|
||||
};
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
getCoordinates() {}
|
||||
|
||||
/**
|
||||
* Set the center (as {@link module:ol/coordinate~Coordinate coordinate}) and the radius (as
|
||||
* number) of the circle.
|
||||
* @param {!module:ol/coordinate~Coordinate} center Center.
|
||||
* @param {number} radius Radius.
|
||||
* @param {module:ol/geom/GeometryLayout=} opt_layout Layout.
|
||||
* @api
|
||||
*/
|
||||
Circle.prototype.setCenterAndRadius = function(center, radius, opt_layout) {
|
||||
this.setLayout(opt_layout, center, 0);
|
||||
if (!this.flatCoordinates) {
|
||||
this.flatCoordinates = [];
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
setCoordinates(coordinates, opt_layout) {}
|
||||
|
||||
/**
|
||||
* Set the radius of the circle. The radius is in the units of the projection.
|
||||
* @param {number} radius Radius.
|
||||
* @api
|
||||
*/
|
||||
setRadius(radius) {
|
||||
this.flatCoordinates[this.stride] = this.flatCoordinates[0] + radius;
|
||||
this.changed();
|
||||
}
|
||||
/** @type {Array.<number>} */
|
||||
const flatCoordinates = this.flatCoordinates;
|
||||
let offset = deflateCoordinate(
|
||||
flatCoordinates, 0, center, this.stride);
|
||||
flatCoordinates[offset++] = flatCoordinates[0] + radius;
|
||||
for (let i = 1, ii = this.stride; i < ii; ++i) {
|
||||
flatCoordinates[offset++] = flatCoordinates[i];
|
||||
}
|
||||
flatCoordinates.length = offset;
|
||||
this.changed();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
Circle.prototype.getCoordinates = function() {};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
Circle.prototype.setCoordinates = function(coordinates, opt_layout) {};
|
||||
|
||||
|
||||
/**
|
||||
* Set the radius of the circle. The radius is in the units of the projection.
|
||||
* @param {number} radius Radius.
|
||||
* @api
|
||||
*/
|
||||
Circle.prototype.setRadius = function(radius) {
|
||||
this.flatCoordinates[this.stride] = this.flatCoordinates[0] + radius;
|
||||
this.changed();
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
/**
|
||||
* @module ol/geom/Geometry
|
||||
*/
|
||||
import {inherits} from '../util.js';
|
||||
import BaseObject from '../Object.js';
|
||||
import {createEmpty, getHeight, returnOrUpdate} from '../extent.js';
|
||||
import {FALSE} from '../functions.js';
|
||||
@@ -11,6 +10,12 @@ import Units from '../proj/Units.js';
|
||||
import {create as createTransform, compose as composeTransform} from '../transform.js';
|
||||
|
||||
|
||||
/**
|
||||
* @type {module:ol/transform~Transform}
|
||||
*/
|
||||
const tmpTransform = createTransform();
|
||||
|
||||
|
||||
/**
|
||||
* @classdesc
|
||||
* Abstract base class; normally only used for creating subclasses and not
|
||||
@@ -20,109 +25,228 @@ import {create as createTransform, compose as composeTransform} from '../transfo
|
||||
* To get notified of changes to the geometry, register a listener for the
|
||||
* generic `change` event on your geometry instance.
|
||||
*
|
||||
* @constructor
|
||||
* @abstract
|
||||
* @extends {module:ol/Object}
|
||||
* @api
|
||||
*/
|
||||
const Geometry = function() {
|
||||
class Geometry extends BaseObject {
|
||||
constructor() {
|
||||
|
||||
BaseObject.call(this);
|
||||
super();
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {module:ol/extent~Extent}
|
||||
*/
|
||||
this.extent_ = createEmpty();
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {number}
|
||||
*/
|
||||
this.extentRevision_ = -1;
|
||||
|
||||
/**
|
||||
* @protected
|
||||
* @type {Object.<string, module:ol/geom/Geometry>}
|
||||
*/
|
||||
this.simplifiedGeometryCache = {};
|
||||
|
||||
/**
|
||||
* @protected
|
||||
* @type {number}
|
||||
*/
|
||||
this.simplifiedGeometryMaxMinSquaredTolerance = 0;
|
||||
|
||||
/**
|
||||
* @protected
|
||||
* @type {number}
|
||||
*/
|
||||
this.simplifiedGeometryRevision = 0;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {module:ol/extent~Extent}
|
||||
* Make a complete copy of the geometry.
|
||||
* @abstract
|
||||
* @return {!module:ol/geom/Geometry} Clone.
|
||||
*/
|
||||
this.extent_ = createEmpty();
|
||||
clone() {}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {number}
|
||||
* @abstract
|
||||
* @param {number} x X.
|
||||
* @param {number} y Y.
|
||||
* @param {module:ol/coordinate~Coordinate} closestPoint Closest point.
|
||||
* @param {number} minSquaredDistance Minimum squared distance.
|
||||
* @return {number} Minimum squared distance.
|
||||
*/
|
||||
this.extentRevision_ = -1;
|
||||
closestPointXY(x, y, closestPoint, minSquaredDistance) {}
|
||||
|
||||
/**
|
||||
* Return the closest point of the geometry to the passed point as
|
||||
* {@link module:ol/coordinate~Coordinate coordinate}.
|
||||
* @param {module:ol/coordinate~Coordinate} point Point.
|
||||
* @param {module:ol/coordinate~Coordinate=} opt_closestPoint Closest point.
|
||||
* @return {module:ol/coordinate~Coordinate} Closest point.
|
||||
* @api
|
||||
*/
|
||||
getClosestPoint(point, opt_closestPoint) {
|
||||
const closestPoint = opt_closestPoint ? opt_closestPoint : [NaN, NaN];
|
||||
this.closestPointXY(point[0], point[1], closestPoint, Infinity);
|
||||
return closestPoint;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this geometry includes the specified coordinate. If the
|
||||
* coordinate is on the boundary of the geometry, returns false.
|
||||
* @param {module:ol/coordinate~Coordinate} coordinate Coordinate.
|
||||
* @return {boolean} Contains coordinate.
|
||||
* @api
|
||||
*/
|
||||
intersectsCoordinate(coordinate) {
|
||||
return this.containsXY(coordinate[0], coordinate[1]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @abstract
|
||||
* @param {module:ol/extent~Extent} extent Extent.
|
||||
* @protected
|
||||
* @type {Object.<string, module:ol/geom/Geometry>}
|
||||
* @return {module:ol/extent~Extent} extent Extent.
|
||||
*/
|
||||
this.simplifiedGeometryCache = {};
|
||||
computeExtent(extent) {}
|
||||
|
||||
/**
|
||||
* @protected
|
||||
* @type {number}
|
||||
* Get the extent of the geometry.
|
||||
* @param {module:ol/extent~Extent=} opt_extent Extent.
|
||||
* @return {module:ol/extent~Extent} extent Extent.
|
||||
* @api
|
||||
*/
|
||||
this.simplifiedGeometryMaxMinSquaredTolerance = 0;
|
||||
getExtent(opt_extent) {
|
||||
if (this.extentRevision_ != this.getRevision()) {
|
||||
this.extent_ = this.computeExtent(this.extent_);
|
||||
this.extentRevision_ = this.getRevision();
|
||||
}
|
||||
return returnOrUpdate(this.extent_, opt_extent);
|
||||
}
|
||||
|
||||
/**
|
||||
* @protected
|
||||
* @type {number}
|
||||
* Rotate the geometry around a given coordinate. This modifies the geometry
|
||||
* coordinates in place.
|
||||
* @abstract
|
||||
* @param {number} angle Rotation angle in radians.
|
||||
* @param {module:ol/coordinate~Coordinate} anchor The rotation center.
|
||||
* @api
|
||||
*/
|
||||
this.simplifiedGeometryRevision = 0;
|
||||
rotate(angle, anchor) {}
|
||||
|
||||
};
|
||||
/**
|
||||
* Scale the geometry (with an optional origin). This modifies the geometry
|
||||
* coordinates in place.
|
||||
* @abstract
|
||||
* @param {number} sx The scaling factor in the x-direction.
|
||||
* @param {number=} opt_sy The scaling factor in the y-direction (defaults to
|
||||
* sx).
|
||||
* @param {module:ol/coordinate~Coordinate=} opt_anchor The scale origin (defaults to the center
|
||||
* of the geometry extent).
|
||||
* @api
|
||||
*/
|
||||
scale(sx, opt_sy, opt_anchor) {}
|
||||
|
||||
inherits(Geometry, BaseObject);
|
||||
/**
|
||||
* Create a simplified version of this geometry. For linestrings, this uses
|
||||
* the the {@link
|
||||
* https://en.wikipedia.org/wiki/Ramer-Douglas-Peucker_algorithm
|
||||
* Douglas Peucker} algorithm. For polygons, a quantization-based
|
||||
* simplification is used to preserve topology.
|
||||
* @function
|
||||
* @param {number} tolerance The tolerance distance for simplification.
|
||||
* @return {module:ol/geom/Geometry} A new, simplified version of the original
|
||||
* geometry.
|
||||
* @api
|
||||
*/
|
||||
simplify(tolerance) {
|
||||
return this.getSimplifiedGeometry(tolerance * tolerance);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a simplified version of this geometry using the Douglas Peucker
|
||||
* algorithm.
|
||||
* @see https://en.wikipedia.org/wiki/Ramer-Douglas-Peucker_algorithm
|
||||
* @abstract
|
||||
* @param {number} squaredTolerance Squared tolerance.
|
||||
* @return {module:ol/geom/Geometry} Simplified geometry.
|
||||
*/
|
||||
getSimplifiedGeometry(squaredTolerance) {}
|
||||
|
||||
/**
|
||||
* @type {module:ol/transform~Transform}
|
||||
*/
|
||||
const tmpTransform = createTransform();
|
||||
/**
|
||||
* Get the type of this geometry.
|
||||
* @abstract
|
||||
* @return {module:ol/geom/GeometryType} Geometry type.
|
||||
*/
|
||||
getType() {}
|
||||
|
||||
/**
|
||||
* Apply a transform function to each coordinate of the geometry.
|
||||
* The geometry is modified in place.
|
||||
* If you do not want the geometry modified in place, first `clone()` it and
|
||||
* then use this function on the clone.
|
||||
* @abstract
|
||||
* @param {module:ol/proj~TransformFunction} transformFn Transform.
|
||||
*/
|
||||
applyTransform(transformFn) {}
|
||||
|
||||
/**
|
||||
* Make a complete copy of the geometry.
|
||||
* @abstract
|
||||
* @return {!module:ol/geom/Geometry} Clone.
|
||||
*/
|
||||
Geometry.prototype.clone = function() {};
|
||||
/**
|
||||
* Test if the geometry and the passed extent intersect.
|
||||
* @abstract
|
||||
* @param {module:ol/extent~Extent} extent Extent.
|
||||
* @return {boolean} `true` if the geometry and the extent intersect.
|
||||
*/
|
||||
intersectsExtent(extent) {}
|
||||
|
||||
/**
|
||||
* Translate the geometry. This modifies the geometry coordinates in place. If
|
||||
* instead you want a new geometry, first `clone()` this geometry.
|
||||
* @abstract
|
||||
* @param {number} deltaX Delta X.
|
||||
* @param {number} deltaY Delta Y.
|
||||
*/
|
||||
translate(deltaX, deltaY) {}
|
||||
|
||||
/**
|
||||
* @abstract
|
||||
* @param {number} x X.
|
||||
* @param {number} y Y.
|
||||
* @param {module:ol/coordinate~Coordinate} closestPoint Closest point.
|
||||
* @param {number} minSquaredDistance Minimum squared distance.
|
||||
* @return {number} Minimum squared distance.
|
||||
*/
|
||||
Geometry.prototype.closestPointXY = function(x, y, closestPoint, minSquaredDistance) {};
|
||||
|
||||
|
||||
/**
|
||||
* Return the closest point of the geometry to the passed point as
|
||||
* {@link module:ol/coordinate~Coordinate coordinate}.
|
||||
* @param {module:ol/coordinate~Coordinate} point Point.
|
||||
* @param {module:ol/coordinate~Coordinate=} opt_closestPoint Closest point.
|
||||
* @return {module:ol/coordinate~Coordinate} Closest point.
|
||||
* @api
|
||||
*/
|
||||
Geometry.prototype.getClosestPoint = function(point, opt_closestPoint) {
|
||||
const closestPoint = opt_closestPoint ? opt_closestPoint : [NaN, NaN];
|
||||
this.closestPointXY(point[0], point[1], closestPoint, Infinity);
|
||||
return closestPoint;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns true if this geometry includes the specified coordinate. If the
|
||||
* coordinate is on the boundary of the geometry, returns false.
|
||||
* @param {module:ol/coordinate~Coordinate} coordinate Coordinate.
|
||||
* @return {boolean} Contains coordinate.
|
||||
* @api
|
||||
*/
|
||||
Geometry.prototype.intersectsCoordinate = function(coordinate) {
|
||||
return this.containsXY(coordinate[0], coordinate[1]);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @abstract
|
||||
* @param {module:ol/extent~Extent} extent Extent.
|
||||
* @protected
|
||||
* @return {module:ol/extent~Extent} extent Extent.
|
||||
*/
|
||||
Geometry.prototype.computeExtent = function(extent) {};
|
||||
/**
|
||||
* Transform each coordinate of the geometry from one coordinate reference
|
||||
* system to another. The geometry is modified in place.
|
||||
* For example, a line will be transformed to a line and a circle to a circle.
|
||||
* If you do not want the geometry modified in place, first `clone()` it and
|
||||
* then use this function on the clone.
|
||||
*
|
||||
* @param {module:ol/proj~ProjectionLike} source The current projection. Can be a
|
||||
* string identifier or a {@link module:ol/proj/Projection~Projection} object.
|
||||
* @param {module:ol/proj~ProjectionLike} destination The desired projection. Can be a
|
||||
* string identifier or a {@link module:ol/proj/Projection~Projection} object.
|
||||
* @return {module:ol/geom/Geometry} This geometry. Note that original geometry is
|
||||
* modified in place.
|
||||
* @api
|
||||
*/
|
||||
transform(source, destination) {
|
||||
source = getProjection(source);
|
||||
const transformFn = source.getUnits() == Units.TILE_PIXELS ?
|
||||
function(inCoordinates, outCoordinates, stride) {
|
||||
const pixelExtent = source.getExtent();
|
||||
const projectedExtent = source.getWorldExtent();
|
||||
const scale = getHeight(projectedExtent) / getHeight(pixelExtent);
|
||||
composeTransform(tmpTransform,
|
||||
projectedExtent[0], projectedExtent[3],
|
||||
scale, -scale, 0,
|
||||
0, 0);
|
||||
transform2D(inCoordinates, 0, inCoordinates.length, stride,
|
||||
tmpTransform, outCoordinates);
|
||||
return getTransform(source, destination)(inCoordinates, outCoordinates, stride);
|
||||
} :
|
||||
getTransform(source, destination);
|
||||
this.applyTransform(transformFn);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
@@ -133,144 +257,4 @@ Geometry.prototype.computeExtent = function(extent) {};
|
||||
Geometry.prototype.containsXY = FALSE;
|
||||
|
||||
|
||||
/**
|
||||
* Get the extent of the geometry.
|
||||
* @param {module:ol/extent~Extent=} opt_extent Extent.
|
||||
* @return {module:ol/extent~Extent} extent Extent.
|
||||
* @api
|
||||
*/
|
||||
Geometry.prototype.getExtent = function(opt_extent) {
|
||||
if (this.extentRevision_ != this.getRevision()) {
|
||||
this.extent_ = this.computeExtent(this.extent_);
|
||||
this.extentRevision_ = this.getRevision();
|
||||
}
|
||||
return returnOrUpdate(this.extent_, opt_extent);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Rotate the geometry around a given coordinate. This modifies the geometry
|
||||
* coordinates in place.
|
||||
* @abstract
|
||||
* @param {number} angle Rotation angle in radians.
|
||||
* @param {module:ol/coordinate~Coordinate} anchor The rotation center.
|
||||
* @api
|
||||
*/
|
||||
Geometry.prototype.rotate = function(angle, anchor) {};
|
||||
|
||||
|
||||
/**
|
||||
* Scale the geometry (with an optional origin). This modifies the geometry
|
||||
* coordinates in place.
|
||||
* @abstract
|
||||
* @param {number} sx The scaling factor in the x-direction.
|
||||
* @param {number=} opt_sy The scaling factor in the y-direction (defaults to
|
||||
* sx).
|
||||
* @param {module:ol/coordinate~Coordinate=} opt_anchor The scale origin (defaults to the center
|
||||
* of the geometry extent).
|
||||
* @api
|
||||
*/
|
||||
Geometry.prototype.scale = function(sx, opt_sy, opt_anchor) {};
|
||||
|
||||
|
||||
/**
|
||||
* Create a simplified version of this geometry. For linestrings, this uses
|
||||
* the the {@link
|
||||
* https://en.wikipedia.org/wiki/Ramer-Douglas-Peucker_algorithm
|
||||
* Douglas Peucker} algorithm. For polygons, a quantization-based
|
||||
* simplification is used to preserve topology.
|
||||
* @function
|
||||
* @param {number} tolerance The tolerance distance for simplification.
|
||||
* @return {module:ol/geom/Geometry} A new, simplified version of the original
|
||||
* geometry.
|
||||
* @api
|
||||
*/
|
||||
Geometry.prototype.simplify = function(tolerance) {
|
||||
return this.getSimplifiedGeometry(tolerance * tolerance);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Create a simplified version of this geometry using the Douglas Peucker
|
||||
* algorithm.
|
||||
* @see https://en.wikipedia.org/wiki/Ramer-Douglas-Peucker_algorithm
|
||||
* @abstract
|
||||
* @param {number} squaredTolerance Squared tolerance.
|
||||
* @return {module:ol/geom/Geometry} Simplified geometry.
|
||||
*/
|
||||
Geometry.prototype.getSimplifiedGeometry = function(squaredTolerance) {};
|
||||
|
||||
|
||||
/**
|
||||
* Get the type of this geometry.
|
||||
* @abstract
|
||||
* @return {module:ol/geom/GeometryType} Geometry type.
|
||||
*/
|
||||
Geometry.prototype.getType = function() {};
|
||||
|
||||
|
||||
/**
|
||||
* Apply a transform function to each coordinate of the geometry.
|
||||
* The geometry is modified in place.
|
||||
* If you do not want the geometry modified in place, first `clone()` it and
|
||||
* then use this function on the clone.
|
||||
* @abstract
|
||||
* @param {module:ol/proj~TransformFunction} transformFn Transform.
|
||||
*/
|
||||
Geometry.prototype.applyTransform = function(transformFn) {};
|
||||
|
||||
|
||||
/**
|
||||
* Test if the geometry and the passed extent intersect.
|
||||
* @abstract
|
||||
* @param {module:ol/extent~Extent} extent Extent.
|
||||
* @return {boolean} `true` if the geometry and the extent intersect.
|
||||
*/
|
||||
Geometry.prototype.intersectsExtent = function(extent) {};
|
||||
|
||||
|
||||
/**
|
||||
* Translate the geometry. This modifies the geometry coordinates in place. If
|
||||
* instead you want a new geometry, first `clone()` this geometry.
|
||||
* @abstract
|
||||
* @param {number} deltaX Delta X.
|
||||
* @param {number} deltaY Delta Y.
|
||||
*/
|
||||
Geometry.prototype.translate = function(deltaX, deltaY) {};
|
||||
|
||||
|
||||
/**
|
||||
* Transform each coordinate of the geometry from one coordinate reference
|
||||
* system to another. The geometry is modified in place.
|
||||
* For example, a line will be transformed to a line and a circle to a circle.
|
||||
* If you do not want the geometry modified in place, first `clone()` it and
|
||||
* then use this function on the clone.
|
||||
*
|
||||
* @param {module:ol/proj~ProjectionLike} source The current projection. Can be a
|
||||
* string identifier or a {@link module:ol/proj/Projection~Projection} object.
|
||||
* @param {module:ol/proj~ProjectionLike} destination The desired projection. Can be a
|
||||
* string identifier or a {@link module:ol/proj/Projection~Projection} object.
|
||||
* @return {module:ol/geom/Geometry} This geometry. Note that original geometry is
|
||||
* modified in place.
|
||||
* @api
|
||||
*/
|
||||
Geometry.prototype.transform = function(source, destination) {
|
||||
source = getProjection(source);
|
||||
const transformFn = source.getUnits() == Units.TILE_PIXELS ?
|
||||
function(inCoordinates, outCoordinates, stride) {
|
||||
const pixelExtent = source.getExtent();
|
||||
const projectedExtent = source.getWorldExtent();
|
||||
const scale = getHeight(projectedExtent) / getHeight(pixelExtent);
|
||||
composeTransform(tmpTransform,
|
||||
projectedExtent[0], projectedExtent[3],
|
||||
scale, -scale, 0,
|
||||
0, 0);
|
||||
transform2D(inCoordinates, 0, inCoordinates.length, stride,
|
||||
tmpTransform, outCoordinates);
|
||||
return getTransform(source, destination)(inCoordinates, outCoordinates, stride);
|
||||
} :
|
||||
getTransform(source, destination);
|
||||
this.applyTransform(transformFn);
|
||||
return this;
|
||||
};
|
||||
export default Geometry;
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
/**
|
||||
* @module ol/geom/GeometryCollection
|
||||
*/
|
||||
import {inherits} from '../util.js';
|
||||
import {listen, unlisten} from '../events.js';
|
||||
import EventType from '../events/EventType.js';
|
||||
import {createOrUpdateEmpty, closestSquaredDistanceXY, extend, getCenter} from '../extent.js';
|
||||
@@ -13,25 +12,274 @@ import {clear} from '../obj.js';
|
||||
* @classdesc
|
||||
* An array of {@link module:ol/geom/Geometry} objects.
|
||||
*
|
||||
* @constructor
|
||||
* @extends {module:ol/geom/Geometry}
|
||||
* @param {Array.<module:ol/geom/Geometry>=} opt_geometries Geometries.
|
||||
* @api
|
||||
*/
|
||||
const GeometryCollection = function(opt_geometries) {
|
||||
class GeometryCollection extends Geometry {
|
||||
|
||||
Geometry.call(this);
|
||||
/**
|
||||
* @param {Array.<module:ol/geom/Geometry>=} opt_geometries Geometries.
|
||||
*/
|
||||
constructor(opt_geometries) {
|
||||
|
||||
super();
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {Array.<module:ol/geom/Geometry>}
|
||||
*/
|
||||
this.geometries_ = opt_geometries ? opt_geometries : null;
|
||||
|
||||
this.listenGeometriesChange_();
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {Array.<module:ol/geom/Geometry>}
|
||||
*/
|
||||
this.geometries_ = opt_geometries ? opt_geometries : null;
|
||||
unlistenGeometriesChange_() {
|
||||
if (!this.geometries_) {
|
||||
return;
|
||||
}
|
||||
for (let i = 0, ii = this.geometries_.length; i < ii; ++i) {
|
||||
unlisten(
|
||||
this.geometries_[i], EventType.CHANGE,
|
||||
this.changed, this);
|
||||
}
|
||||
}
|
||||
|
||||
this.listenGeometriesChange_();
|
||||
};
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
listenGeometriesChange_() {
|
||||
if (!this.geometries_) {
|
||||
return;
|
||||
}
|
||||
for (let i = 0, ii = this.geometries_.length; i < ii; ++i) {
|
||||
listen(
|
||||
this.geometries_[i], EventType.CHANGE,
|
||||
this.changed, this);
|
||||
}
|
||||
}
|
||||
|
||||
inherits(GeometryCollection, Geometry);
|
||||
/**
|
||||
* Make a complete copy of the geometry.
|
||||
* @return {!module:ol/geom/GeometryCollection} Clone.
|
||||
* @override
|
||||
* @api
|
||||
*/
|
||||
clone() {
|
||||
const geometryCollection = new GeometryCollection(null);
|
||||
geometryCollection.setGeometries(this.geometries_);
|
||||
return geometryCollection;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
closestPointXY(x, y, closestPoint, minSquaredDistance) {
|
||||
if (minSquaredDistance < closestSquaredDistanceXY(this.getExtent(), x, y)) {
|
||||
return minSquaredDistance;
|
||||
}
|
||||
const geometries = this.geometries_;
|
||||
for (let i = 0, ii = geometries.length; i < ii; ++i) {
|
||||
minSquaredDistance = geometries[i].closestPointXY(
|
||||
x, y, closestPoint, minSquaredDistance);
|
||||
}
|
||||
return minSquaredDistance;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
containsXY(x, y) {
|
||||
const geometries = this.geometries_;
|
||||
for (let i = 0, ii = geometries.length; i < ii; ++i) {
|
||||
if (geometries[i].containsXY(x, y)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
computeExtent(extent) {
|
||||
createOrUpdateEmpty(extent);
|
||||
const geometries = this.geometries_;
|
||||
for (let i = 0, ii = geometries.length; i < ii; ++i) {
|
||||
extend(extent, geometries[i].getExtent());
|
||||
}
|
||||
return extent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the geometries that make up this geometry collection.
|
||||
* @return {Array.<module:ol/geom/Geometry>} Geometries.
|
||||
* @api
|
||||
*/
|
||||
getGeometries() {
|
||||
return cloneGeometries(this.geometries_);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {Array.<module:ol/geom/Geometry>} Geometries.
|
||||
*/
|
||||
getGeometriesArray() {
|
||||
return this.geometries_;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
getSimplifiedGeometry(squaredTolerance) {
|
||||
if (this.simplifiedGeometryRevision != this.getRevision()) {
|
||||
clear(this.simplifiedGeometryCache);
|
||||
this.simplifiedGeometryMaxMinSquaredTolerance = 0;
|
||||
this.simplifiedGeometryRevision = this.getRevision();
|
||||
}
|
||||
if (squaredTolerance < 0 ||
|
||||
(this.simplifiedGeometryMaxMinSquaredTolerance !== 0 &&
|
||||
squaredTolerance < this.simplifiedGeometryMaxMinSquaredTolerance)) {
|
||||
return this;
|
||||
}
|
||||
const key = squaredTolerance.toString();
|
||||
if (this.simplifiedGeometryCache.hasOwnProperty(key)) {
|
||||
return this.simplifiedGeometryCache[key];
|
||||
} else {
|
||||
const simplifiedGeometries = [];
|
||||
const geometries = this.geometries_;
|
||||
let simplified = false;
|
||||
for (let i = 0, ii = geometries.length; i < ii; ++i) {
|
||||
const geometry = geometries[i];
|
||||
const simplifiedGeometry = geometry.getSimplifiedGeometry(squaredTolerance);
|
||||
simplifiedGeometries.push(simplifiedGeometry);
|
||||
if (simplifiedGeometry !== geometry) {
|
||||
simplified = true;
|
||||
}
|
||||
}
|
||||
if (simplified) {
|
||||
const simplifiedGeometryCollection = new GeometryCollection(null);
|
||||
simplifiedGeometryCollection.setGeometriesArray(simplifiedGeometries);
|
||||
this.simplifiedGeometryCache[key] = simplifiedGeometryCollection;
|
||||
return simplifiedGeometryCollection;
|
||||
} else {
|
||||
this.simplifiedGeometryMaxMinSquaredTolerance = squaredTolerance;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @api
|
||||
*/
|
||||
getType() {
|
||||
return GeometryType.GEOMETRY_COLLECTION;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @api
|
||||
*/
|
||||
intersectsExtent(extent) {
|
||||
const geometries = this.geometries_;
|
||||
for (let i = 0, ii = geometries.length; i < ii; ++i) {
|
||||
if (geometries[i].intersectsExtent(extent)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {boolean} Is empty.
|
||||
*/
|
||||
isEmpty() {
|
||||
return this.geometries_.length === 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @api
|
||||
*/
|
||||
rotate(angle, anchor) {
|
||||
const geometries = this.geometries_;
|
||||
for (let i = 0, ii = geometries.length; i < ii; ++i) {
|
||||
geometries[i].rotate(angle, anchor);
|
||||
}
|
||||
this.changed();
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @api
|
||||
*/
|
||||
scale(sx, opt_sy, opt_anchor) {
|
||||
let anchor = opt_anchor;
|
||||
if (!anchor) {
|
||||
anchor = getCenter(this.getExtent());
|
||||
}
|
||||
const geometries = this.geometries_;
|
||||
for (let i = 0, ii = geometries.length; i < ii; ++i) {
|
||||
geometries[i].scale(sx, opt_sy, anchor);
|
||||
}
|
||||
this.changed();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the geometries that make up this geometry collection.
|
||||
* @param {Array.<module:ol/geom/Geometry>} geometries Geometries.
|
||||
* @api
|
||||
*/
|
||||
setGeometries(geometries) {
|
||||
this.setGeometriesArray(cloneGeometries(geometries));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Array.<module:ol/geom/Geometry>} geometries Geometries.
|
||||
*/
|
||||
setGeometriesArray(geometries) {
|
||||
this.unlistenGeometriesChange_();
|
||||
this.geometries_ = geometries;
|
||||
this.listenGeometriesChange_();
|
||||
this.changed();
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @api
|
||||
*/
|
||||
applyTransform(transformFn) {
|
||||
const geometries = this.geometries_;
|
||||
for (let i = 0, ii = geometries.length; i < ii; ++i) {
|
||||
geometries[i].applyTransform(transformFn);
|
||||
}
|
||||
this.changed();
|
||||
}
|
||||
|
||||
/**
|
||||
* Translate the geometry.
|
||||
* @param {number} deltaX Delta X.
|
||||
* @param {number} deltaY Delta Y.
|
||||
* @override
|
||||
* @api
|
||||
*/
|
||||
translate(deltaX, deltaY) {
|
||||
const geometries = this.geometries_;
|
||||
for (let i = 0, ii = geometries.length; i < ii; ++i) {
|
||||
geometries[i].translate(deltaX, deltaY);
|
||||
}
|
||||
this.changed();
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
disposeInternal() {
|
||||
this.unlistenGeometriesChange_();
|
||||
Geometry.prototype.disposeInternal.call(this);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
@@ -47,269 +295,4 @@ function cloneGeometries(geometries) {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
GeometryCollection.prototype.unlistenGeometriesChange_ = function() {
|
||||
if (!this.geometries_) {
|
||||
return;
|
||||
}
|
||||
for (let i = 0, ii = this.geometries_.length; i < ii; ++i) {
|
||||
unlisten(
|
||||
this.geometries_[i], EventType.CHANGE,
|
||||
this.changed, this);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
GeometryCollection.prototype.listenGeometriesChange_ = function() {
|
||||
if (!this.geometries_) {
|
||||
return;
|
||||
}
|
||||
for (let i = 0, ii = this.geometries_.length; i < ii; ++i) {
|
||||
listen(
|
||||
this.geometries_[i], EventType.CHANGE,
|
||||
this.changed, this);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Make a complete copy of the geometry.
|
||||
* @return {!module:ol/geom/GeometryCollection} Clone.
|
||||
* @override
|
||||
* @api
|
||||
*/
|
||||
GeometryCollection.prototype.clone = function() {
|
||||
const geometryCollection = new GeometryCollection(null);
|
||||
geometryCollection.setGeometries(this.geometries_);
|
||||
return geometryCollection;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
GeometryCollection.prototype.closestPointXY = function(x, y, closestPoint, minSquaredDistance) {
|
||||
if (minSquaredDistance < closestSquaredDistanceXY(this.getExtent(), x, y)) {
|
||||
return minSquaredDistance;
|
||||
}
|
||||
const geometries = this.geometries_;
|
||||
for (let i = 0, ii = geometries.length; i < ii; ++i) {
|
||||
minSquaredDistance = geometries[i].closestPointXY(
|
||||
x, y, closestPoint, minSquaredDistance);
|
||||
}
|
||||
return minSquaredDistance;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
GeometryCollection.prototype.containsXY = function(x, y) {
|
||||
const geometries = this.geometries_;
|
||||
for (let i = 0, ii = geometries.length; i < ii; ++i) {
|
||||
if (geometries[i].containsXY(x, y)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
GeometryCollection.prototype.computeExtent = function(extent) {
|
||||
createOrUpdateEmpty(extent);
|
||||
const geometries = this.geometries_;
|
||||
for (let i = 0, ii = geometries.length; i < ii; ++i) {
|
||||
extend(extent, geometries[i].getExtent());
|
||||
}
|
||||
return extent;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Return the geometries that make up this geometry collection.
|
||||
* @return {Array.<module:ol/geom/Geometry>} Geometries.
|
||||
* @api
|
||||
*/
|
||||
GeometryCollection.prototype.getGeometries = function() {
|
||||
return cloneGeometries(this.geometries_);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {Array.<module:ol/geom/Geometry>} Geometries.
|
||||
*/
|
||||
GeometryCollection.prototype.getGeometriesArray = function() {
|
||||
return this.geometries_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
GeometryCollection.prototype.getSimplifiedGeometry = function(squaredTolerance) {
|
||||
if (this.simplifiedGeometryRevision != this.getRevision()) {
|
||||
clear(this.simplifiedGeometryCache);
|
||||
this.simplifiedGeometryMaxMinSquaredTolerance = 0;
|
||||
this.simplifiedGeometryRevision = this.getRevision();
|
||||
}
|
||||
if (squaredTolerance < 0 ||
|
||||
(this.simplifiedGeometryMaxMinSquaredTolerance !== 0 &&
|
||||
squaredTolerance < this.simplifiedGeometryMaxMinSquaredTolerance)) {
|
||||
return this;
|
||||
}
|
||||
const key = squaredTolerance.toString();
|
||||
if (this.simplifiedGeometryCache.hasOwnProperty(key)) {
|
||||
return this.simplifiedGeometryCache[key];
|
||||
} else {
|
||||
const simplifiedGeometries = [];
|
||||
const geometries = this.geometries_;
|
||||
let simplified = false;
|
||||
for (let i = 0, ii = geometries.length; i < ii; ++i) {
|
||||
const geometry = geometries[i];
|
||||
const simplifiedGeometry = geometry.getSimplifiedGeometry(squaredTolerance);
|
||||
simplifiedGeometries.push(simplifiedGeometry);
|
||||
if (simplifiedGeometry !== geometry) {
|
||||
simplified = true;
|
||||
}
|
||||
}
|
||||
if (simplified) {
|
||||
const simplifiedGeometryCollection = new GeometryCollection(null);
|
||||
simplifiedGeometryCollection.setGeometriesArray(simplifiedGeometries);
|
||||
this.simplifiedGeometryCache[key] = simplifiedGeometryCollection;
|
||||
return simplifiedGeometryCollection;
|
||||
} else {
|
||||
this.simplifiedGeometryMaxMinSquaredTolerance = squaredTolerance;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @api
|
||||
*/
|
||||
GeometryCollection.prototype.getType = function() {
|
||||
return GeometryType.GEOMETRY_COLLECTION;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @api
|
||||
*/
|
||||
GeometryCollection.prototype.intersectsExtent = function(extent) {
|
||||
const geometries = this.geometries_;
|
||||
for (let i = 0, ii = geometries.length; i < ii; ++i) {
|
||||
if (geometries[i].intersectsExtent(extent)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {boolean} Is empty.
|
||||
*/
|
||||
GeometryCollection.prototype.isEmpty = function() {
|
||||
return this.geometries_.length === 0;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @api
|
||||
*/
|
||||
GeometryCollection.prototype.rotate = function(angle, anchor) {
|
||||
const geometries = this.geometries_;
|
||||
for (let i = 0, ii = geometries.length; i < ii; ++i) {
|
||||
geometries[i].rotate(angle, anchor);
|
||||
}
|
||||
this.changed();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @api
|
||||
*/
|
||||
GeometryCollection.prototype.scale = function(sx, opt_sy, opt_anchor) {
|
||||
let anchor = opt_anchor;
|
||||
if (!anchor) {
|
||||
anchor = getCenter(this.getExtent());
|
||||
}
|
||||
const geometries = this.geometries_;
|
||||
for (let i = 0, ii = geometries.length; i < ii; ++i) {
|
||||
geometries[i].scale(sx, opt_sy, anchor);
|
||||
}
|
||||
this.changed();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Set the geometries that make up this geometry collection.
|
||||
* @param {Array.<module:ol/geom/Geometry>} geometries Geometries.
|
||||
* @api
|
||||
*/
|
||||
GeometryCollection.prototype.setGeometries = function(geometries) {
|
||||
this.setGeometriesArray(cloneGeometries(geometries));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {Array.<module:ol/geom/Geometry>} geometries Geometries.
|
||||
*/
|
||||
GeometryCollection.prototype.setGeometriesArray = function(geometries) {
|
||||
this.unlistenGeometriesChange_();
|
||||
this.geometries_ = geometries;
|
||||
this.listenGeometriesChange_();
|
||||
this.changed();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @api
|
||||
*/
|
||||
GeometryCollection.prototype.applyTransform = function(transformFn) {
|
||||
const geometries = this.geometries_;
|
||||
for (let i = 0, ii = geometries.length; i < ii; ++i) {
|
||||
geometries[i].applyTransform(transformFn);
|
||||
}
|
||||
this.changed();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Translate the geometry.
|
||||
* @param {number} deltaX Delta X.
|
||||
* @param {number} deltaY Delta Y.
|
||||
* @override
|
||||
* @api
|
||||
*/
|
||||
GeometryCollection.prototype.translate = function(deltaX, deltaY) {
|
||||
const geometries = this.geometries_;
|
||||
for (let i = 0, ii = geometries.length; i < ii; ++i) {
|
||||
geometries[i].translate(deltaX, deltaY);
|
||||
}
|
||||
this.changed();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
GeometryCollection.prototype.disposeInternal = function() {
|
||||
this.unlistenGeometriesChange_();
|
||||
Geometry.prototype.disposeInternal.call(this);
|
||||
};
|
||||
export default GeometryCollection;
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
/**
|
||||
* @module ol/geom/LineString
|
||||
*/
|
||||
import {inherits} from '../util.js';
|
||||
import {extend} from '../array.js';
|
||||
import {closestSquaredDistanceXY} from '../extent.js';
|
||||
import GeometryLayout from '../geom/GeometryLayout.js';
|
||||
@@ -20,237 +19,225 @@ import {douglasPeucker} from '../geom/flat/simplify.js';
|
||||
* @classdesc
|
||||
* Linestring geometry.
|
||||
*
|
||||
* @constructor
|
||||
* @extends {module:ol/geom/SimpleGeometry}
|
||||
* @param {Array.<module:ol/coordinate~Coordinate>|Array.<number>} coordinates
|
||||
* Coordinates. (For internal use, flat coordinates in combination with
|
||||
* `opt_layout` are also accepted).
|
||||
* @param {module:ol/geom/GeometryLayout=} opt_layout Layout.
|
||||
* @api
|
||||
*/
|
||||
const LineString = function(coordinates, opt_layout) {
|
||||
|
||||
SimpleGeometry.call(this);
|
||||
class LineString extends SimpleGeometry {
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {module:ol/coordinate~Coordinate}
|
||||
* @param {Array.<module:ol/coordinate~Coordinate>|Array.<number>} coordinates Coordinates.
|
||||
* For internal use, flat coordinates in combination with `opt_layout` are also accepted.
|
||||
* @param {module:ol/geom/GeometryLayout=} opt_layout Layout.
|
||||
*/
|
||||
this.flatMidpoint_ = null;
|
||||
constructor(coordinates, opt_layout) {
|
||||
|
||||
super();
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {module:ol/coordinate~Coordinate}
|
||||
*/
|
||||
this.flatMidpoint_ = null;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {number}
|
||||
*/
|
||||
this.flatMidpointRevision_ = -1;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {number}
|
||||
*/
|
||||
this.maxDelta_ = -1;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {number}
|
||||
*/
|
||||
this.maxDeltaRevision_ = -1;
|
||||
|
||||
if (opt_layout !== undefined && !Array.isArray(coordinates[0])) {
|
||||
this.setFlatCoordinates(opt_layout, coordinates);
|
||||
} else {
|
||||
this.setCoordinates(coordinates, opt_layout);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {number}
|
||||
* Append the passed coordinate to the coordinates of the linestring.
|
||||
* @param {module:ol/coordinate~Coordinate} coordinate Coordinate.
|
||||
* @api
|
||||
*/
|
||||
this.flatMidpointRevision_ = -1;
|
||||
appendCoordinate(coordinate) {
|
||||
if (!this.flatCoordinates) {
|
||||
this.flatCoordinates = coordinate.slice();
|
||||
} else {
|
||||
extend(this.flatCoordinates, coordinate);
|
||||
}
|
||||
this.changed();
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {number}
|
||||
* Make a complete copy of the geometry.
|
||||
* @return {!module:ol/geom/LineString} Clone.
|
||||
* @override
|
||||
* @api
|
||||
*/
|
||||
this.maxDelta_ = -1;
|
||||
clone() {
|
||||
return new LineString(this.flatCoordinates.slice(), this.layout);
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {number}
|
||||
* @inheritDoc
|
||||
*/
|
||||
this.maxDeltaRevision_ = -1;
|
||||
|
||||
if (opt_layout !== undefined && !Array.isArray(coordinates[0])) {
|
||||
this.setFlatCoordinates(opt_layout, coordinates);
|
||||
} else {
|
||||
this.setCoordinates(coordinates, opt_layout);
|
||||
closestPointXY(x, y, closestPoint, minSquaredDistance) {
|
||||
if (minSquaredDistance < closestSquaredDistanceXY(this.getExtent(), x, y)) {
|
||||
return minSquaredDistance;
|
||||
}
|
||||
if (this.maxDeltaRevision_ != this.getRevision()) {
|
||||
this.maxDelta_ = Math.sqrt(maxSquaredDelta(
|
||||
this.flatCoordinates, 0, this.flatCoordinates.length, this.stride, 0));
|
||||
this.maxDeltaRevision_ = this.getRevision();
|
||||
}
|
||||
return assignClosestPoint(
|
||||
this.flatCoordinates, 0, this.flatCoordinates.length, this.stride,
|
||||
this.maxDelta_, false, x, y, closestPoint, minSquaredDistance);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
inherits(LineString, SimpleGeometry);
|
||||
|
||||
|
||||
/**
|
||||
* Append the passed coordinate to the coordinates of the linestring.
|
||||
* @param {module:ol/coordinate~Coordinate} coordinate Coordinate.
|
||||
* @api
|
||||
*/
|
||||
LineString.prototype.appendCoordinate = function(coordinate) {
|
||||
if (!this.flatCoordinates) {
|
||||
this.flatCoordinates = coordinate.slice();
|
||||
} else {
|
||||
extend(this.flatCoordinates, coordinate);
|
||||
/**
|
||||
* Iterate over each segment, calling the provided callback.
|
||||
* If the callback returns a truthy value the function returns that
|
||||
* value immediately. Otherwise the function returns `false`.
|
||||
*
|
||||
* @param {function(this: S, module:ol/coordinate~Coordinate, module:ol/coordinate~Coordinate): T} callback Function
|
||||
* called for each segment.
|
||||
* @return {T|boolean} Value.
|
||||
* @template T,S
|
||||
* @api
|
||||
*/
|
||||
forEachSegment(callback) {
|
||||
return forEachSegment(this.flatCoordinates, 0, this.flatCoordinates.length, this.stride, callback);
|
||||
}
|
||||
this.changed();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Make a complete copy of the geometry.
|
||||
* @return {!module:ol/geom/LineString} Clone.
|
||||
* @override
|
||||
* @api
|
||||
*/
|
||||
LineString.prototype.clone = function() {
|
||||
return new LineString(this.flatCoordinates.slice(), this.layout);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
LineString.prototype.closestPointXY = function(x, y, closestPoint, minSquaredDistance) {
|
||||
if (minSquaredDistance < closestSquaredDistanceXY(this.getExtent(), x, y)) {
|
||||
return minSquaredDistance;
|
||||
/**
|
||||
* Returns the coordinate at `m` using linear interpolation, or `null` if no
|
||||
* such coordinate exists.
|
||||
*
|
||||
* `opt_extrapolate` controls extrapolation beyond the range of Ms in the
|
||||
* MultiLineString. If `opt_extrapolate` is `true` then Ms less than the first
|
||||
* M will return the first coordinate and Ms greater than the last M will
|
||||
* return the last coordinate.
|
||||
*
|
||||
* @param {number} m M.
|
||||
* @param {boolean=} opt_extrapolate Extrapolate. Default is `false`.
|
||||
* @return {module:ol/coordinate~Coordinate} Coordinate.
|
||||
* @api
|
||||
*/
|
||||
getCoordinateAtM(m, opt_extrapolate) {
|
||||
if (this.layout != GeometryLayout.XYM &&
|
||||
this.layout != GeometryLayout.XYZM) {
|
||||
return null;
|
||||
}
|
||||
const extrapolate = opt_extrapolate !== undefined ? opt_extrapolate : false;
|
||||
return lineStringCoordinateAtM(this.flatCoordinates, 0,
|
||||
this.flatCoordinates.length, this.stride, m, extrapolate);
|
||||
}
|
||||
if (this.maxDeltaRevision_ != this.getRevision()) {
|
||||
this.maxDelta_ = Math.sqrt(maxSquaredDelta(
|
||||
this.flatCoordinates, 0, this.flatCoordinates.length, this.stride, 0));
|
||||
this.maxDeltaRevision_ = this.getRevision();
|
||||
|
||||
/**
|
||||
* Return the coordinates of the linestring.
|
||||
* @return {Array.<module:ol/coordinate~Coordinate>} Coordinates.
|
||||
* @override
|
||||
* @api
|
||||
*/
|
||||
getCoordinates() {
|
||||
return inflateCoordinates(
|
||||
this.flatCoordinates, 0, this.flatCoordinates.length, this.stride);
|
||||
}
|
||||
return assignClosestPoint(
|
||||
this.flatCoordinates, 0, this.flatCoordinates.length, this.stride,
|
||||
this.maxDelta_, false, x, y, closestPoint, minSquaredDistance);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Iterate over each segment, calling the provided callback.
|
||||
* If the callback returns a truthy value the function returns that
|
||||
* value immediately. Otherwise the function returns `false`.
|
||||
*
|
||||
* @param {function(this: S, module:ol/coordinate~Coordinate, module:ol/coordinate~Coordinate): T} callback Function
|
||||
* called for each segment.
|
||||
* @return {T|boolean} Value.
|
||||
* @template T,S
|
||||
* @api
|
||||
*/
|
||||
LineString.prototype.forEachSegment = function(callback) {
|
||||
return forEachSegment(this.flatCoordinates, 0, this.flatCoordinates.length, this.stride, callback);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns the coordinate at `m` using linear interpolation, or `null` if no
|
||||
* such coordinate exists.
|
||||
*
|
||||
* `opt_extrapolate` controls extrapolation beyond the range of Ms in the
|
||||
* MultiLineString. If `opt_extrapolate` is `true` then Ms less than the first
|
||||
* M will return the first coordinate and Ms greater than the last M will
|
||||
* return the last coordinate.
|
||||
*
|
||||
* @param {number} m M.
|
||||
* @param {boolean=} opt_extrapolate Extrapolate. Default is `false`.
|
||||
* @return {module:ol/coordinate~Coordinate} Coordinate.
|
||||
* @api
|
||||
*/
|
||||
LineString.prototype.getCoordinateAtM = function(m, opt_extrapolate) {
|
||||
if (this.layout != GeometryLayout.XYM &&
|
||||
this.layout != GeometryLayout.XYZM) {
|
||||
return null;
|
||||
/**
|
||||
* Return the coordinate at the provided fraction along the linestring.
|
||||
* The `fraction` is a number between 0 and 1, where 0 is the start of the
|
||||
* linestring and 1 is the end.
|
||||
* @param {number} fraction Fraction.
|
||||
* @param {module:ol/coordinate~Coordinate=} opt_dest Optional coordinate whose values will
|
||||
* be modified. If not provided, a new coordinate will be returned.
|
||||
* @return {module:ol/coordinate~Coordinate} Coordinate of the interpolated point.
|
||||
* @api
|
||||
*/
|
||||
getCoordinateAt(fraction, opt_dest) {
|
||||
return interpolatePoint(
|
||||
this.flatCoordinates, 0, this.flatCoordinates.length, this.stride,
|
||||
fraction, opt_dest);
|
||||
}
|
||||
const extrapolate = opt_extrapolate !== undefined ? opt_extrapolate : false;
|
||||
return lineStringCoordinateAtM(this.flatCoordinates, 0,
|
||||
this.flatCoordinates.length, this.stride, m, extrapolate);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Return the coordinates of the linestring.
|
||||
* @return {Array.<module:ol/coordinate~Coordinate>} Coordinates.
|
||||
* @override
|
||||
* @api
|
||||
*/
|
||||
LineString.prototype.getCoordinates = function() {
|
||||
return inflateCoordinates(
|
||||
this.flatCoordinates, 0, this.flatCoordinates.length, this.stride);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Return the coordinate at the provided fraction along the linestring.
|
||||
* The `fraction` is a number between 0 and 1, where 0 is the start of the
|
||||
* linestring and 1 is the end.
|
||||
* @param {number} fraction Fraction.
|
||||
* @param {module:ol/coordinate~Coordinate=} opt_dest Optional coordinate whose values will
|
||||
* be modified. If not provided, a new coordinate will be returned.
|
||||
* @return {module:ol/coordinate~Coordinate} Coordinate of the interpolated point.
|
||||
* @api
|
||||
*/
|
||||
LineString.prototype.getCoordinateAt = function(fraction, opt_dest) {
|
||||
return interpolatePoint(
|
||||
this.flatCoordinates, 0, this.flatCoordinates.length, this.stride,
|
||||
fraction, opt_dest);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Return the length of the linestring on projected plane.
|
||||
* @return {number} Length (on projected plane).
|
||||
* @api
|
||||
*/
|
||||
LineString.prototype.getLength = function() {
|
||||
return lineStringLength(
|
||||
this.flatCoordinates, 0, this.flatCoordinates.length, this.stride);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {Array.<number>} Flat midpoint.
|
||||
*/
|
||||
LineString.prototype.getFlatMidpoint = function() {
|
||||
if (this.flatMidpointRevision_ != this.getRevision()) {
|
||||
this.flatMidpoint_ = this.getCoordinateAt(0.5, this.flatMidpoint_);
|
||||
this.flatMidpointRevision_ = this.getRevision();
|
||||
/**
|
||||
* Return the length of the linestring on projected plane.
|
||||
* @return {number} Length (on projected plane).
|
||||
* @api
|
||||
*/
|
||||
getLength() {
|
||||
return lineStringLength(
|
||||
this.flatCoordinates, 0, this.flatCoordinates.length, this.stride);
|
||||
}
|
||||
return this.flatMidpoint_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
LineString.prototype.getSimplifiedGeometryInternal = function(squaredTolerance) {
|
||||
const simplifiedFlatCoordinates = [];
|
||||
simplifiedFlatCoordinates.length = douglasPeucker(
|
||||
this.flatCoordinates, 0, this.flatCoordinates.length, this.stride,
|
||||
squaredTolerance, simplifiedFlatCoordinates, 0);
|
||||
return new LineString(simplifiedFlatCoordinates, GeometryLayout.XY);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @api
|
||||
*/
|
||||
LineString.prototype.getType = function() {
|
||||
return GeometryType.LINE_STRING;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @api
|
||||
*/
|
||||
LineString.prototype.intersectsExtent = function(extent) {
|
||||
return intersectsLineString(
|
||||
this.flatCoordinates, 0, this.flatCoordinates.length, this.stride,
|
||||
extent);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Set the coordinates of the linestring.
|
||||
* @param {!Array.<module:ol/coordinate~Coordinate>} coordinates Coordinates.
|
||||
* @param {module:ol/geom/GeometryLayout=} opt_layout Layout.
|
||||
* @override
|
||||
* @api
|
||||
*/
|
||||
LineString.prototype.setCoordinates = function(coordinates, opt_layout) {
|
||||
this.setLayout(opt_layout, coordinates, 1);
|
||||
if (!this.flatCoordinates) {
|
||||
this.flatCoordinates = [];
|
||||
/**
|
||||
* @return {Array.<number>} Flat midpoint.
|
||||
*/
|
||||
getFlatMidpoint() {
|
||||
if (this.flatMidpointRevision_ != this.getRevision()) {
|
||||
this.flatMidpoint_ = this.getCoordinateAt(0.5, this.flatMidpoint_);
|
||||
this.flatMidpointRevision_ = this.getRevision();
|
||||
}
|
||||
return this.flatMidpoint_;
|
||||
}
|
||||
this.flatCoordinates.length = deflateCoordinates(
|
||||
this.flatCoordinates, 0, coordinates, this.stride);
|
||||
this.changed();
|
||||
};
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
getSimplifiedGeometryInternal(squaredTolerance) {
|
||||
const simplifiedFlatCoordinates = [];
|
||||
simplifiedFlatCoordinates.length = douglasPeucker(
|
||||
this.flatCoordinates, 0, this.flatCoordinates.length, this.stride,
|
||||
squaredTolerance, simplifiedFlatCoordinates, 0);
|
||||
return new LineString(simplifiedFlatCoordinates, GeometryLayout.XY);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @api
|
||||
*/
|
||||
getType() {
|
||||
return GeometryType.LINE_STRING;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @api
|
||||
*/
|
||||
intersectsExtent(extent) {
|
||||
return intersectsLineString(
|
||||
this.flatCoordinates, 0, this.flatCoordinates.length, this.stride,
|
||||
extent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the coordinates of the linestring.
|
||||
* @param {!Array.<module:ol/coordinate~Coordinate>} coordinates Coordinates.
|
||||
* @param {module:ol/geom/GeometryLayout=} opt_layout Layout.
|
||||
* @override
|
||||
* @api
|
||||
*/
|
||||
setCoordinates(coordinates, opt_layout) {
|
||||
this.setLayout(opt_layout, coordinates, 1);
|
||||
if (!this.flatCoordinates) {
|
||||
this.flatCoordinates = [];
|
||||
}
|
||||
this.flatCoordinates.length = deflateCoordinates(
|
||||
this.flatCoordinates, 0, coordinates, this.stride);
|
||||
this.changed();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export default LineString;
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
/**
|
||||
* @module ol/geom/LinearRing
|
||||
*/
|
||||
import {inherits} from '../util.js';
|
||||
import {closestSquaredDistanceXY} from '../extent.js';
|
||||
import GeometryLayout from '../geom/GeometryLayout.js';
|
||||
import GeometryType from '../geom/GeometryType.js';
|
||||
@@ -17,133 +16,127 @@ import {douglasPeucker} from '../geom/flat/simplify.js';
|
||||
* Linear ring geometry. Only used as part of polygon; cannot be rendered
|
||||
* on its own.
|
||||
*
|
||||
* @constructor
|
||||
* @extends {module:ol/geom/SimpleGeometry}
|
||||
* @param {Array.<module:ol/coordinate~Coordinate>|Array.<number>} coordinates
|
||||
* Coordinates. (For internal use, flat coordinates in combination with
|
||||
* `opt_layout` are also accepted.)
|
||||
* @param {module:ol/geom/GeometryLayout=} opt_layout Layout.
|
||||
* @api
|
||||
*/
|
||||
const LinearRing = function(coordinates, opt_layout) {
|
||||
|
||||
SimpleGeometry.call(this);
|
||||
class LinearRing extends SimpleGeometry {
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {number}
|
||||
* @param {Array.<module:ol/coordinate~Coordinate>|Array.<number>} coordinates Coordinates.
|
||||
* For internal use, flat coordinates in combination with `opt_layout` are also accepted.
|
||||
* @param {module:ol/geom/GeometryLayout=} opt_layout Layout.
|
||||
*/
|
||||
this.maxDelta_ = -1;
|
||||
constructor(coordinates, opt_layout) {
|
||||
|
||||
super();
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {number}
|
||||
*/
|
||||
this.maxDelta_ = -1;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {number}
|
||||
*/
|
||||
this.maxDeltaRevision_ = -1;
|
||||
|
||||
if (opt_layout !== undefined && !Array.isArray(coordinates[0])) {
|
||||
this.setFlatCoordinates(opt_layout, coordinates);
|
||||
} else {
|
||||
this.setCoordinates(coordinates, opt_layout);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {number}
|
||||
* Make a complete copy of the geometry.
|
||||
* @return {!module:ol/geom/LinearRing} Clone.
|
||||
* @override
|
||||
* @api
|
||||
*/
|
||||
this.maxDeltaRevision_ = -1;
|
||||
|
||||
if (opt_layout !== undefined && !Array.isArray(coordinates[0])) {
|
||||
this.setFlatCoordinates(opt_layout, coordinates);
|
||||
} else {
|
||||
this.setCoordinates(coordinates, opt_layout);
|
||||
clone() {
|
||||
return new LinearRing(this.flatCoordinates.slice(), this.layout);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
inherits(LinearRing, SimpleGeometry);
|
||||
|
||||
|
||||
/**
|
||||
* Make a complete copy of the geometry.
|
||||
* @return {!module:ol/geom/LinearRing} Clone.
|
||||
* @override
|
||||
* @api
|
||||
*/
|
||||
LinearRing.prototype.clone = function() {
|
||||
return new LinearRing(this.flatCoordinates.slice(), this.layout);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
LinearRing.prototype.closestPointXY = function(x, y, closestPoint, minSquaredDistance) {
|
||||
if (minSquaredDistance < closestSquaredDistanceXY(this.getExtent(), x, y)) {
|
||||
return minSquaredDistance;
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
closestPointXY(x, y, closestPoint, minSquaredDistance) {
|
||||
if (minSquaredDistance < closestSquaredDistanceXY(this.getExtent(), x, y)) {
|
||||
return minSquaredDistance;
|
||||
}
|
||||
if (this.maxDeltaRevision_ != this.getRevision()) {
|
||||
this.maxDelta_ = Math.sqrt(maxSquaredDelta(
|
||||
this.flatCoordinates, 0, this.flatCoordinates.length, this.stride, 0));
|
||||
this.maxDeltaRevision_ = this.getRevision();
|
||||
}
|
||||
return assignClosestPoint(
|
||||
this.flatCoordinates, 0, this.flatCoordinates.length, this.stride,
|
||||
this.maxDelta_, true, x, y, closestPoint, minSquaredDistance);
|
||||
}
|
||||
if (this.maxDeltaRevision_ != this.getRevision()) {
|
||||
this.maxDelta_ = Math.sqrt(maxSquaredDelta(
|
||||
this.flatCoordinates, 0, this.flatCoordinates.length, this.stride, 0));
|
||||
this.maxDeltaRevision_ = this.getRevision();
|
||||
|
||||
/**
|
||||
* Return the area of the linear ring on projected plane.
|
||||
* @return {number} Area (on projected plane).
|
||||
* @api
|
||||
*/
|
||||
getArea() {
|
||||
return linearRingArea(this.flatCoordinates, 0, this.flatCoordinates.length, this.stride);
|
||||
}
|
||||
return assignClosestPoint(
|
||||
this.flatCoordinates, 0, this.flatCoordinates.length, this.stride,
|
||||
this.maxDelta_, true, x, y, closestPoint, minSquaredDistance);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Return the area of the linear ring on projected plane.
|
||||
* @return {number} Area (on projected plane).
|
||||
* @api
|
||||
*/
|
||||
LinearRing.prototype.getArea = function() {
|
||||
return linearRingArea(this.flatCoordinates, 0, this.flatCoordinates.length, this.stride);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Return the coordinates of the linear ring.
|
||||
* @return {Array.<module:ol/coordinate~Coordinate>} Coordinates.
|
||||
* @override
|
||||
* @api
|
||||
*/
|
||||
LinearRing.prototype.getCoordinates = function() {
|
||||
return inflateCoordinates(
|
||||
this.flatCoordinates, 0, this.flatCoordinates.length, this.stride);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
LinearRing.prototype.getSimplifiedGeometryInternal = function(squaredTolerance) {
|
||||
const simplifiedFlatCoordinates = [];
|
||||
simplifiedFlatCoordinates.length = douglasPeucker(
|
||||
this.flatCoordinates, 0, this.flatCoordinates.length, this.stride,
|
||||
squaredTolerance, simplifiedFlatCoordinates, 0);
|
||||
return new LinearRing(simplifiedFlatCoordinates, GeometryLayout.XY);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @api
|
||||
*/
|
||||
LinearRing.prototype.getType = function() {
|
||||
return GeometryType.LINEAR_RING;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
LinearRing.prototype.intersectsExtent = function(extent) {};
|
||||
|
||||
|
||||
/**
|
||||
* Set the coordinates of the linear ring.
|
||||
* @param {!Array.<module:ol/coordinate~Coordinate>} coordinates Coordinates.
|
||||
* @param {module:ol/geom/GeometryLayout=} opt_layout Layout.
|
||||
* @override
|
||||
* @api
|
||||
*/
|
||||
LinearRing.prototype.setCoordinates = function(coordinates, opt_layout) {
|
||||
this.setLayout(opt_layout, coordinates, 1);
|
||||
if (!this.flatCoordinates) {
|
||||
this.flatCoordinates = [];
|
||||
/**
|
||||
* Return the coordinates of the linear ring.
|
||||
* @return {Array.<module:ol/coordinate~Coordinate>} Coordinates.
|
||||
* @override
|
||||
* @api
|
||||
*/
|
||||
getCoordinates() {
|
||||
return inflateCoordinates(
|
||||
this.flatCoordinates, 0, this.flatCoordinates.length, this.stride);
|
||||
}
|
||||
this.flatCoordinates.length = deflateCoordinates(
|
||||
this.flatCoordinates, 0, coordinates, this.stride);
|
||||
this.changed();
|
||||
};
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
getSimplifiedGeometryInternal(squaredTolerance) {
|
||||
const simplifiedFlatCoordinates = [];
|
||||
simplifiedFlatCoordinates.length = douglasPeucker(
|
||||
this.flatCoordinates, 0, this.flatCoordinates.length, this.stride,
|
||||
squaredTolerance, simplifiedFlatCoordinates, 0);
|
||||
return new LinearRing(simplifiedFlatCoordinates, GeometryLayout.XY);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @api
|
||||
*/
|
||||
getType() {
|
||||
return GeometryType.LINEAR_RING;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
intersectsExtent(extent) {}
|
||||
|
||||
/**
|
||||
* Set the coordinates of the linear ring.
|
||||
* @param {!Array.<module:ol/coordinate~Coordinate>} coordinates Coordinates.
|
||||
* @param {module:ol/geom/GeometryLayout=} opt_layout Layout.
|
||||
* @override
|
||||
* @api
|
||||
*/
|
||||
setCoordinates(coordinates, opt_layout) {
|
||||
this.setLayout(opt_layout, coordinates, 1);
|
||||
if (!this.flatCoordinates) {
|
||||
this.flatCoordinates = [];
|
||||
}
|
||||
this.flatCoordinates.length = deflateCoordinates(
|
||||
this.flatCoordinates, 0, coordinates, this.stride);
|
||||
this.changed();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export default LinearRing;
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
/**
|
||||
* @module ol/geom/MultiLineString
|
||||
*/
|
||||
import {inherits} from '../util.js';
|
||||
import {extend} from '../array.js';
|
||||
import {closestSquaredDistanceXY} from '../extent.js';
|
||||
import GeometryLayout from '../geom/GeometryLayout.js';
|
||||
@@ -19,267 +18,257 @@ import {douglasPeuckerArray} from '../geom/flat/simplify.js';
|
||||
* @classdesc
|
||||
* Multi-linestring geometry.
|
||||
*
|
||||
* @constructor
|
||||
* @extends {module:ol/geom/SimpleGeometry}
|
||||
* @param {Array.<Array.<module:ol/coordinate~Coordinate>|module:ol/geom~MultiLineString>|Array.<number>} coordinates
|
||||
* Coordinates or LineString geometries. (For internal use, flat coordinates in
|
||||
* combination with `opt_layout` and `opt_ends` are also accepted.)
|
||||
* @param {module:ol/geom/GeometryLayout=} opt_layout Layout.
|
||||
* @param {Array.<number>} opt_ends Flat coordinate ends for internal use.
|
||||
* @api
|
||||
*/
|
||||
const MultiLineString = function(coordinates, opt_layout, opt_ends) {
|
||||
|
||||
SimpleGeometry.call(this);
|
||||
class MultiLineString extends SimpleGeometry {
|
||||
|
||||
/**
|
||||
* @type {Array.<number>}
|
||||
* @private
|
||||
* @param {Array.<Array.<module:ol/coordinate~Coordinate>|module:ol/geom~MultiLineString>|Array.<number>} coordinates
|
||||
* Coordinates or LineString geometries. (For internal use, flat coordinates in
|
||||
* combination with `opt_layout` and `opt_ends` are also accepted.)
|
||||
* @param {module:ol/geom/GeometryLayout=} opt_layout Layout.
|
||||
* @param {Array.<number>} opt_ends Flat coordinate ends for internal use.
|
||||
*/
|
||||
this.ends_ = [];
|
||||
constructor(coordinates, opt_layout, opt_ends) {
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {number}
|
||||
*/
|
||||
this.maxDelta_ = -1;
|
||||
super();
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {number}
|
||||
*/
|
||||
this.maxDeltaRevision_ = -1;
|
||||
/**
|
||||
* @type {Array.<number>}
|
||||
* @private
|
||||
*/
|
||||
this.ends_ = [];
|
||||
|
||||
if (Array.isArray(coordinates[0])) {
|
||||
this.setCoordinates(coordinates, opt_layout);
|
||||
} else if (opt_layout !== undefined && opt_ends) {
|
||||
this.setFlatCoordinates(opt_layout, coordinates);
|
||||
this.ends_ = opt_ends;
|
||||
} else {
|
||||
let layout = this.getLayout();
|
||||
const flatCoordinates = [];
|
||||
const ends = [];
|
||||
for (let i = 0, ii = coordinates.length; i < ii; ++i) {
|
||||
const lineString = coordinates[i];
|
||||
if (i === 0) {
|
||||
layout = lineString.getLayout();
|
||||
/**
|
||||
* @private
|
||||
* @type {number}
|
||||
*/
|
||||
this.maxDelta_ = -1;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {number}
|
||||
*/
|
||||
this.maxDeltaRevision_ = -1;
|
||||
|
||||
if (Array.isArray(coordinates[0])) {
|
||||
this.setCoordinates(coordinates, opt_layout);
|
||||
} else if (opt_layout !== undefined && opt_ends) {
|
||||
this.setFlatCoordinates(opt_layout, coordinates);
|
||||
this.ends_ = opt_ends;
|
||||
} else {
|
||||
let layout = this.getLayout();
|
||||
const flatCoordinates = [];
|
||||
const ends = [];
|
||||
for (let i = 0, ii = coordinates.length; i < ii; ++i) {
|
||||
const lineString = coordinates[i];
|
||||
if (i === 0) {
|
||||
layout = lineString.getLayout();
|
||||
}
|
||||
extend(flatCoordinates, lineString.getFlatCoordinates());
|
||||
ends.push(flatCoordinates.length);
|
||||
}
|
||||
extend(flatCoordinates, lineString.getFlatCoordinates());
|
||||
ends.push(flatCoordinates.length);
|
||||
this.setFlatCoordinates(layout, flatCoordinates);
|
||||
this.ends_ = ends;
|
||||
}
|
||||
this.setFlatCoordinates(layout, flatCoordinates);
|
||||
this.ends_ = ends;
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
inherits(MultiLineString, SimpleGeometry);
|
||||
|
||||
|
||||
/**
|
||||
* Append the passed linestring to the multilinestring.
|
||||
* @param {module:ol/geom/LineString} lineString LineString.
|
||||
* @api
|
||||
*/
|
||||
MultiLineString.prototype.appendLineString = function(lineString) {
|
||||
if (!this.flatCoordinates) {
|
||||
this.flatCoordinates = lineString.getFlatCoordinates().slice();
|
||||
} else {
|
||||
extend(this.flatCoordinates, lineString.getFlatCoordinates().slice());
|
||||
/**
|
||||
* Append the passed linestring to the multilinestring.
|
||||
* @param {module:ol/geom/LineString} lineString LineString.
|
||||
* @api
|
||||
*/
|
||||
appendLineString(lineString) {
|
||||
if (!this.flatCoordinates) {
|
||||
this.flatCoordinates = lineString.getFlatCoordinates().slice();
|
||||
} else {
|
||||
extend(this.flatCoordinates, lineString.getFlatCoordinates().slice());
|
||||
}
|
||||
this.ends_.push(this.flatCoordinates.length);
|
||||
this.changed();
|
||||
}
|
||||
this.ends_.push(this.flatCoordinates.length);
|
||||
this.changed();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Make a complete copy of the geometry.
|
||||
* @return {!module:ol/geom/MultiLineString} Clone.
|
||||
* @override
|
||||
* @api
|
||||
*/
|
||||
MultiLineString.prototype.clone = function() {
|
||||
return new MultiLineString(this.flatCoordinates.slice(), this.layout, this.ends_.slice());
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
MultiLineString.prototype.closestPointXY = function(x, y, closestPoint, minSquaredDistance) {
|
||||
if (minSquaredDistance < closestSquaredDistanceXY(this.getExtent(), x, y)) {
|
||||
return minSquaredDistance;
|
||||
/**
|
||||
* Make a complete copy of the geometry.
|
||||
* @return {!module:ol/geom/MultiLineString} Clone.
|
||||
* @override
|
||||
* @api
|
||||
*/
|
||||
clone() {
|
||||
return new MultiLineString(this.flatCoordinates.slice(), this.layout, this.ends_.slice());
|
||||
}
|
||||
if (this.maxDeltaRevision_ != this.getRevision()) {
|
||||
this.maxDelta_ = Math.sqrt(arrayMaxSquaredDelta(
|
||||
this.flatCoordinates, 0, this.ends_, this.stride, 0));
|
||||
this.maxDeltaRevision_ = this.getRevision();
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
closestPointXY(x, y, closestPoint, minSquaredDistance) {
|
||||
if (minSquaredDistance < closestSquaredDistanceXY(this.getExtent(), x, y)) {
|
||||
return minSquaredDistance;
|
||||
}
|
||||
if (this.maxDeltaRevision_ != this.getRevision()) {
|
||||
this.maxDelta_ = Math.sqrt(arrayMaxSquaredDelta(
|
||||
this.flatCoordinates, 0, this.ends_, this.stride, 0));
|
||||
this.maxDeltaRevision_ = this.getRevision();
|
||||
}
|
||||
return assignClosestArrayPoint(
|
||||
this.flatCoordinates, 0, this.ends_, this.stride,
|
||||
this.maxDelta_, false, x, y, closestPoint, minSquaredDistance);
|
||||
}
|
||||
return assignClosestArrayPoint(
|
||||
this.flatCoordinates, 0, this.ends_, this.stride,
|
||||
this.maxDelta_, false, x, y, closestPoint, minSquaredDistance);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns the coordinate at `m` using linear interpolation, or `null` if no
|
||||
* such coordinate exists.
|
||||
*
|
||||
* `opt_extrapolate` controls extrapolation beyond the range of Ms in the
|
||||
* MultiLineString. If `opt_extrapolate` is `true` then Ms less than the first
|
||||
* M will return the first coordinate and Ms greater than the last M will
|
||||
* return the last coordinate.
|
||||
*
|
||||
* `opt_interpolate` controls interpolation between consecutive LineStrings
|
||||
* within the MultiLineString. If `opt_interpolate` is `true` the coordinates
|
||||
* will be linearly interpolated between the last coordinate of one LineString
|
||||
* and the first coordinate of the next LineString. If `opt_interpolate` is
|
||||
* `false` then the function will return `null` for Ms falling between
|
||||
* LineStrings.
|
||||
*
|
||||
* @param {number} m M.
|
||||
* @param {boolean=} opt_extrapolate Extrapolate. Default is `false`.
|
||||
* @param {boolean=} opt_interpolate Interpolate. Default is `false`.
|
||||
* @return {module:ol/coordinate~Coordinate} Coordinate.
|
||||
* @api
|
||||
*/
|
||||
MultiLineString.prototype.getCoordinateAtM = function(m, opt_extrapolate, opt_interpolate) {
|
||||
if ((this.layout != GeometryLayout.XYM &&
|
||||
this.layout != GeometryLayout.XYZM) ||
|
||||
this.flatCoordinates.length === 0) {
|
||||
return null;
|
||||
/**
|
||||
* Returns the coordinate at `m` using linear interpolation, or `null` if no
|
||||
* such coordinate exists.
|
||||
*
|
||||
* `opt_extrapolate` controls extrapolation beyond the range of Ms in the
|
||||
* MultiLineString. If `opt_extrapolate` is `true` then Ms less than the first
|
||||
* M will return the first coordinate and Ms greater than the last M will
|
||||
* return the last coordinate.
|
||||
*
|
||||
* `opt_interpolate` controls interpolation between consecutive LineStrings
|
||||
* within the MultiLineString. If `opt_interpolate` is `true` the coordinates
|
||||
* will be linearly interpolated between the last coordinate of one LineString
|
||||
* and the first coordinate of the next LineString. If `opt_interpolate` is
|
||||
* `false` then the function will return `null` for Ms falling between
|
||||
* LineStrings.
|
||||
*
|
||||
* @param {number} m M.
|
||||
* @param {boolean=} opt_extrapolate Extrapolate. Default is `false`.
|
||||
* @param {boolean=} opt_interpolate Interpolate. Default is `false`.
|
||||
* @return {module:ol/coordinate~Coordinate} Coordinate.
|
||||
* @api
|
||||
*/
|
||||
getCoordinateAtM(m, opt_extrapolate, opt_interpolate) {
|
||||
if ((this.layout != GeometryLayout.XYM &&
|
||||
this.layout != GeometryLayout.XYZM) ||
|
||||
this.flatCoordinates.length === 0) {
|
||||
return null;
|
||||
}
|
||||
const extrapolate = opt_extrapolate !== undefined ? opt_extrapolate : false;
|
||||
const interpolate = opt_interpolate !== undefined ? opt_interpolate : false;
|
||||
return lineStringsCoordinateAtM(this.flatCoordinates, 0,
|
||||
this.ends_, this.stride, m, extrapolate, interpolate);
|
||||
}
|
||||
const extrapolate = opt_extrapolate !== undefined ? opt_extrapolate : false;
|
||||
const interpolate = opt_interpolate !== undefined ? opt_interpolate : false;
|
||||
return lineStringsCoordinateAtM(this.flatCoordinates, 0,
|
||||
this.ends_, this.stride, m, extrapolate, interpolate);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Return the coordinates of the multilinestring.
|
||||
* @return {Array.<Array.<module:ol/coordinate~Coordinate>>} Coordinates.
|
||||
* @override
|
||||
* @api
|
||||
*/
|
||||
MultiLineString.prototype.getCoordinates = function() {
|
||||
return inflateCoordinatesArray(
|
||||
this.flatCoordinates, 0, this.ends_, this.stride);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {Array.<number>} Ends.
|
||||
*/
|
||||
MultiLineString.prototype.getEnds = function() {
|
||||
return this.ends_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Return the linestring at the specified index.
|
||||
* @param {number} index Index.
|
||||
* @return {module:ol/geom/LineString} LineString.
|
||||
* @api
|
||||
*/
|
||||
MultiLineString.prototype.getLineString = function(index) {
|
||||
if (index < 0 || this.ends_.length <= index) {
|
||||
return null;
|
||||
/**
|
||||
* Return the coordinates of the multilinestring.
|
||||
* @return {Array.<Array.<module:ol/coordinate~Coordinate>>} Coordinates.
|
||||
* @override
|
||||
* @api
|
||||
*/
|
||||
getCoordinates() {
|
||||
return inflateCoordinatesArray(
|
||||
this.flatCoordinates, 0, this.ends_, this.stride);
|
||||
}
|
||||
return new LineString(this.flatCoordinates.slice(
|
||||
index === 0 ? 0 : this.ends_[index - 1], this.ends_[index]), this.layout);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Return the linestrings of this multilinestring.
|
||||
* @return {Array.<module:ol/geom/LineString>} LineStrings.
|
||||
* @api
|
||||
*/
|
||||
MultiLineString.prototype.getLineStrings = function() {
|
||||
const flatCoordinates = this.flatCoordinates;
|
||||
const ends = this.ends_;
|
||||
const layout = this.layout;
|
||||
/** @type {Array.<module:ol/geom/LineString>} */
|
||||
const lineStrings = [];
|
||||
let offset = 0;
|
||||
for (let i = 0, ii = ends.length; i < ii; ++i) {
|
||||
const end = ends[i];
|
||||
const lineString = new LineString(flatCoordinates.slice(offset, end), layout);
|
||||
lineStrings.push(lineString);
|
||||
offset = end;
|
||||
/**
|
||||
* @return {Array.<number>} Ends.
|
||||
*/
|
||||
getEnds() {
|
||||
return this.ends_;
|
||||
}
|
||||
return lineStrings;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {Array.<number>} Flat midpoints.
|
||||
*/
|
||||
MultiLineString.prototype.getFlatMidpoints = function() {
|
||||
const midpoints = [];
|
||||
const flatCoordinates = this.flatCoordinates;
|
||||
let offset = 0;
|
||||
const ends = this.ends_;
|
||||
const stride = this.stride;
|
||||
for (let i = 0, ii = ends.length; i < ii; ++i) {
|
||||
const end = ends[i];
|
||||
const midpoint = interpolatePoint(
|
||||
flatCoordinates, offset, end, stride, 0.5);
|
||||
extend(midpoints, midpoint);
|
||||
offset = end;
|
||||
/**
|
||||
* Return the linestring at the specified index.
|
||||
* @param {number} index Index.
|
||||
* @return {module:ol/geom/LineString} LineString.
|
||||
* @api
|
||||
*/
|
||||
getLineString(index) {
|
||||
if (index < 0 || this.ends_.length <= index) {
|
||||
return null;
|
||||
}
|
||||
return new LineString(this.flatCoordinates.slice(
|
||||
index === 0 ? 0 : this.ends_[index - 1], this.ends_[index]), this.layout);
|
||||
}
|
||||
return midpoints;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
MultiLineString.prototype.getSimplifiedGeometryInternal = function(squaredTolerance) {
|
||||
const simplifiedFlatCoordinates = [];
|
||||
const simplifiedEnds = [];
|
||||
simplifiedFlatCoordinates.length = douglasPeuckerArray(
|
||||
this.flatCoordinates, 0, this.ends_, this.stride, squaredTolerance,
|
||||
simplifiedFlatCoordinates, 0, simplifiedEnds);
|
||||
return new MultiLineString(simplifiedFlatCoordinates, GeometryLayout.XY, simplifiedEnds);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @api
|
||||
*/
|
||||
MultiLineString.prototype.getType = function() {
|
||||
return GeometryType.MULTI_LINE_STRING;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @api
|
||||
*/
|
||||
MultiLineString.prototype.intersectsExtent = function(extent) {
|
||||
return intersectsLineStringArray(
|
||||
this.flatCoordinates, 0, this.ends_, this.stride, extent);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Set the coordinates of the multilinestring.
|
||||
* @param {!Array.<Array.<module:ol/coordinate~Coordinate>>} coordinates Coordinates.
|
||||
* @param {module:ol/geom/GeometryLayout=} opt_layout Layout.
|
||||
* @override
|
||||
* @api
|
||||
*/
|
||||
MultiLineString.prototype.setCoordinates = function(coordinates, opt_layout) {
|
||||
this.setLayout(opt_layout, coordinates, 2);
|
||||
if (!this.flatCoordinates) {
|
||||
this.flatCoordinates = [];
|
||||
/**
|
||||
* Return the linestrings of this multilinestring.
|
||||
* @return {Array.<module:ol/geom/LineString>} LineStrings.
|
||||
* @api
|
||||
*/
|
||||
getLineStrings() {
|
||||
const flatCoordinates = this.flatCoordinates;
|
||||
const ends = this.ends_;
|
||||
const layout = this.layout;
|
||||
/** @type {Array.<module:ol/geom/LineString>} */
|
||||
const lineStrings = [];
|
||||
let offset = 0;
|
||||
for (let i = 0, ii = ends.length; i < ii; ++i) {
|
||||
const end = ends[i];
|
||||
const lineString = new LineString(flatCoordinates.slice(offset, end), layout);
|
||||
lineStrings.push(lineString);
|
||||
offset = end;
|
||||
}
|
||||
return lineStrings;
|
||||
}
|
||||
const ends = deflateCoordinatesArray(
|
||||
this.flatCoordinates, 0, coordinates, this.stride, this.ends_);
|
||||
this.flatCoordinates.length = ends.length === 0 ? 0 : ends[ends.length - 1];
|
||||
this.changed();
|
||||
};
|
||||
|
||||
/**
|
||||
* @return {Array.<number>} Flat midpoints.
|
||||
*/
|
||||
getFlatMidpoints() {
|
||||
const midpoints = [];
|
||||
const flatCoordinates = this.flatCoordinates;
|
||||
let offset = 0;
|
||||
const ends = this.ends_;
|
||||
const stride = this.stride;
|
||||
for (let i = 0, ii = ends.length; i < ii; ++i) {
|
||||
const end = ends[i];
|
||||
const midpoint = interpolatePoint(
|
||||
flatCoordinates, offset, end, stride, 0.5);
|
||||
extend(midpoints, midpoint);
|
||||
offset = end;
|
||||
}
|
||||
return midpoints;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
getSimplifiedGeometryInternal(squaredTolerance) {
|
||||
const simplifiedFlatCoordinates = [];
|
||||
const simplifiedEnds = [];
|
||||
simplifiedFlatCoordinates.length = douglasPeuckerArray(
|
||||
this.flatCoordinates, 0, this.ends_, this.stride, squaredTolerance,
|
||||
simplifiedFlatCoordinates, 0, simplifiedEnds);
|
||||
return new MultiLineString(simplifiedFlatCoordinates, GeometryLayout.XY, simplifiedEnds);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @api
|
||||
*/
|
||||
getType() {
|
||||
return GeometryType.MULTI_LINE_STRING;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @api
|
||||
*/
|
||||
intersectsExtent(extent) {
|
||||
return intersectsLineStringArray(
|
||||
this.flatCoordinates, 0, this.ends_, this.stride, extent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the coordinates of the multilinestring.
|
||||
* @param {!Array.<Array.<module:ol/coordinate~Coordinate>>} coordinates Coordinates.
|
||||
* @param {module:ol/geom/GeometryLayout=} opt_layout Layout.
|
||||
* @override
|
||||
* @api
|
||||
*/
|
||||
setCoordinates(coordinates, opt_layout) {
|
||||
this.setLayout(opt_layout, coordinates, 2);
|
||||
if (!this.flatCoordinates) {
|
||||
this.flatCoordinates = [];
|
||||
}
|
||||
const ends = deflateCoordinatesArray(
|
||||
this.flatCoordinates, 0, coordinates, this.stride, this.ends_);
|
||||
this.flatCoordinates.length = ends.length === 0 ? 0 : ends[ends.length - 1];
|
||||
this.changed();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export default MultiLineString;
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
/**
|
||||
* @module ol/geom/MultiPoint
|
||||
*/
|
||||
import {inherits} from '../util.js';
|
||||
import {extend} from '../array.js';
|
||||
import {closestSquaredDistanceXY, containsXY} from '../extent.js';
|
||||
import GeometryType from '../geom/GeometryType.js';
|
||||
@@ -15,165 +14,158 @@ import {squaredDistance as squaredDx} from '../math.js';
|
||||
* @classdesc
|
||||
* Multi-point geometry.
|
||||
*
|
||||
* @constructor
|
||||
* @extends {module:ol/geom/SimpleGeometry}
|
||||
* @param {Array.<module:ol/coordinate~Coordinate>|Array.<number>} coordinates
|
||||
* Coordinates. (For internal use, flat coordinates in combination with
|
||||
* `opt_layout` are also accepted)
|
||||
* @param {module:ol/geom/GeometryLayout=} opt_layout Layout.
|
||||
* @api
|
||||
*/
|
||||
const MultiPoint = function(coordinates, opt_layout) {
|
||||
SimpleGeometry.call(this);
|
||||
if (opt_layout && !Array.isArray(coordinates[0])) {
|
||||
this.setFlatCoordinates(opt_layout, coordinates);
|
||||
} else {
|
||||
this.setCoordinates(coordinates, opt_layout);
|
||||
class MultiPoint extends SimpleGeometry {
|
||||
|
||||
/**
|
||||
* @param {Array.<module:ol/coordinate~Coordinate>|Array.<number>} coordinates Coordinates.
|
||||
* For internal use, flat coordinates in combination with `opt_layout` are also accepted.
|
||||
* @param {module:ol/geom/GeometryLayout=} opt_layout Layout.
|
||||
*/
|
||||
constructor(coordinates, opt_layout) {
|
||||
super();
|
||||
if (opt_layout && !Array.isArray(coordinates[0])) {
|
||||
this.setFlatCoordinates(opt_layout, coordinates);
|
||||
} else {
|
||||
this.setCoordinates(coordinates, opt_layout);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
inherits(MultiPoint, SimpleGeometry);
|
||||
|
||||
|
||||
/**
|
||||
* Append the passed point to this multipoint.
|
||||
* @param {module:ol/geom/Point} point Point.
|
||||
* @api
|
||||
*/
|
||||
MultiPoint.prototype.appendPoint = function(point) {
|
||||
if (!this.flatCoordinates) {
|
||||
this.flatCoordinates = point.getFlatCoordinates().slice();
|
||||
} else {
|
||||
extend(this.flatCoordinates, point.getFlatCoordinates());
|
||||
/**
|
||||
* Append the passed point to this multipoint.
|
||||
* @param {module:ol/geom/Point} point Point.
|
||||
* @api
|
||||
*/
|
||||
appendPoint(point) {
|
||||
if (!this.flatCoordinates) {
|
||||
this.flatCoordinates = point.getFlatCoordinates().slice();
|
||||
} else {
|
||||
extend(this.flatCoordinates, point.getFlatCoordinates());
|
||||
}
|
||||
this.changed();
|
||||
}
|
||||
this.changed();
|
||||
};
|
||||
|
||||
/**
|
||||
* Make a complete copy of the geometry.
|
||||
* @return {!module:ol/geom/MultiPoint} Clone.
|
||||
* @override
|
||||
* @api
|
||||
*/
|
||||
clone() {
|
||||
const multiPoint = new MultiPoint(this.flatCoordinates.slice(), this.layout);
|
||||
return multiPoint;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make a complete copy of the geometry.
|
||||
* @return {!module:ol/geom/MultiPoint} Clone.
|
||||
* @override
|
||||
* @api
|
||||
*/
|
||||
MultiPoint.prototype.clone = function() {
|
||||
const multiPoint = new MultiPoint(this.flatCoordinates.slice(), this.layout);
|
||||
return multiPoint;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
MultiPoint.prototype.closestPointXY = function(x, y, closestPoint, minSquaredDistance) {
|
||||
if (minSquaredDistance < closestSquaredDistanceXY(this.getExtent(), x, y)) {
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
closestPointXY(x, y, closestPoint, minSquaredDistance) {
|
||||
if (minSquaredDistance < closestSquaredDistanceXY(this.getExtent(), x, y)) {
|
||||
return minSquaredDistance;
|
||||
}
|
||||
const flatCoordinates = this.flatCoordinates;
|
||||
const stride = this.stride;
|
||||
for (let i = 0, ii = flatCoordinates.length; i < ii; i += stride) {
|
||||
const squaredDistance = squaredDx(
|
||||
x, y, flatCoordinates[i], flatCoordinates[i + 1]);
|
||||
if (squaredDistance < minSquaredDistance) {
|
||||
minSquaredDistance = squaredDistance;
|
||||
for (let j = 0; j < stride; ++j) {
|
||||
closestPoint[j] = flatCoordinates[i + j];
|
||||
}
|
||||
closestPoint.length = stride;
|
||||
}
|
||||
}
|
||||
return minSquaredDistance;
|
||||
}
|
||||
const flatCoordinates = this.flatCoordinates;
|
||||
const stride = this.stride;
|
||||
for (let i = 0, ii = flatCoordinates.length; i < ii; i += stride) {
|
||||
const squaredDistance = squaredDx(
|
||||
x, y, flatCoordinates[i], flatCoordinates[i + 1]);
|
||||
if (squaredDistance < minSquaredDistance) {
|
||||
minSquaredDistance = squaredDistance;
|
||||
for (let j = 0; j < stride; ++j) {
|
||||
closestPoint[j] = flatCoordinates[i + j];
|
||||
|
||||
/**
|
||||
* Return the coordinates of the multipoint.
|
||||
* @return {Array.<module:ol/coordinate~Coordinate>} Coordinates.
|
||||
* @override
|
||||
* @api
|
||||
*/
|
||||
getCoordinates() {
|
||||
return inflateCoordinates(
|
||||
this.flatCoordinates, 0, this.flatCoordinates.length, this.stride);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the point at the specified index.
|
||||
* @param {number} index Index.
|
||||
* @return {module:ol/geom/Point} Point.
|
||||
* @api
|
||||
*/
|
||||
getPoint(index) {
|
||||
const n = !this.flatCoordinates ? 0 : this.flatCoordinates.length / this.stride;
|
||||
if (index < 0 || n <= index) {
|
||||
return null;
|
||||
}
|
||||
return new Point(this.flatCoordinates.slice(
|
||||
index * this.stride, (index + 1) * this.stride), this.layout);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the points of this multipoint.
|
||||
* @return {Array.<module:ol/geom/Point>} Points.
|
||||
* @api
|
||||
*/
|
||||
getPoints() {
|
||||
const flatCoordinates = this.flatCoordinates;
|
||||
const layout = this.layout;
|
||||
const stride = this.stride;
|
||||
/** @type {Array.<module:ol/geom/Point>} */
|
||||
const points = [];
|
||||
for (let i = 0, ii = flatCoordinates.length; i < ii; i += stride) {
|
||||
const point = new Point(flatCoordinates.slice(i, i + stride), layout);
|
||||
points.push(point);
|
||||
}
|
||||
return points;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @api
|
||||
*/
|
||||
getType() {
|
||||
return GeometryType.MULTI_POINT;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @api
|
||||
*/
|
||||
intersectsExtent(extent) {
|
||||
const flatCoordinates = this.flatCoordinates;
|
||||
const stride = this.stride;
|
||||
for (let i = 0, ii = flatCoordinates.length; i < ii; i += stride) {
|
||||
const x = flatCoordinates[i];
|
||||
const y = flatCoordinates[i + 1];
|
||||
if (containsXY(extent, x, y)) {
|
||||
return true;
|
||||
}
|
||||
closestPoint.length = stride;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return minSquaredDistance;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Return the coordinates of the multipoint.
|
||||
* @return {Array.<module:ol/coordinate~Coordinate>} Coordinates.
|
||||
* @override
|
||||
* @api
|
||||
*/
|
||||
MultiPoint.prototype.getCoordinates = function() {
|
||||
return inflateCoordinates(
|
||||
this.flatCoordinates, 0, this.flatCoordinates.length, this.stride);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Return the point at the specified index.
|
||||
* @param {number} index Index.
|
||||
* @return {module:ol/geom/Point} Point.
|
||||
* @api
|
||||
*/
|
||||
MultiPoint.prototype.getPoint = function(index) {
|
||||
const n = !this.flatCoordinates ? 0 : this.flatCoordinates.length / this.stride;
|
||||
if (index < 0 || n <= index) {
|
||||
return null;
|
||||
}
|
||||
return new Point(this.flatCoordinates.slice(
|
||||
index * this.stride, (index + 1) * this.stride), this.layout);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Return the points of this multipoint.
|
||||
* @return {Array.<module:ol/geom/Point>} Points.
|
||||
* @api
|
||||
*/
|
||||
MultiPoint.prototype.getPoints = function() {
|
||||
const flatCoordinates = this.flatCoordinates;
|
||||
const layout = this.layout;
|
||||
const stride = this.stride;
|
||||
/** @type {Array.<module:ol/geom/Point>} */
|
||||
const points = [];
|
||||
for (let i = 0, ii = flatCoordinates.length; i < ii; i += stride) {
|
||||
const point = new Point(flatCoordinates.slice(i, i + stride), layout);
|
||||
points.push(point);
|
||||
}
|
||||
return points;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @api
|
||||
*/
|
||||
MultiPoint.prototype.getType = function() {
|
||||
return GeometryType.MULTI_POINT;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @api
|
||||
*/
|
||||
MultiPoint.prototype.intersectsExtent = function(extent) {
|
||||
const flatCoordinates = this.flatCoordinates;
|
||||
const stride = this.stride;
|
||||
for (let i = 0, ii = flatCoordinates.length; i < ii; i += stride) {
|
||||
const x = flatCoordinates[i];
|
||||
const y = flatCoordinates[i + 1];
|
||||
if (containsXY(extent, x, y)) {
|
||||
return true;
|
||||
/**
|
||||
* Set the coordinates of the multipoint.
|
||||
* @param {!Array.<module:ol/coordinate~Coordinate>} coordinates Coordinates.
|
||||
* @param {module:ol/geom/GeometryLayout=} opt_layout Layout.
|
||||
* @override
|
||||
* @api
|
||||
*/
|
||||
setCoordinates(coordinates, opt_layout) {
|
||||
this.setLayout(opt_layout, coordinates, 1);
|
||||
if (!this.flatCoordinates) {
|
||||
this.flatCoordinates = [];
|
||||
}
|
||||
this.flatCoordinates.length = deflateCoordinates(
|
||||
this.flatCoordinates, 0, coordinates, this.stride);
|
||||
this.changed();
|
||||
}
|
||||
return false;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the coordinates of the multipoint.
|
||||
* @param {!Array.<module:ol/coordinate~Coordinate>} coordinates Coordinates.
|
||||
* @param {module:ol/geom/GeometryLayout=} opt_layout Layout.
|
||||
* @override
|
||||
* @api
|
||||
*/
|
||||
MultiPoint.prototype.setCoordinates = function(coordinates, opt_layout) {
|
||||
this.setLayout(opt_layout, coordinates, 1);
|
||||
if (!this.flatCoordinates) {
|
||||
this.flatCoordinates = [];
|
||||
}
|
||||
this.flatCoordinates.length = deflateCoordinates(
|
||||
this.flatCoordinates, 0, coordinates, this.stride);
|
||||
this.changed();
|
||||
};
|
||||
export default MultiPoint;
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
/**
|
||||
* @module ol/geom/MultiPolygon
|
||||
*/
|
||||
import {inherits} from '../util.js';
|
||||
import {extend} from '../array.js';
|
||||
import {closestSquaredDistanceXY} from '../extent.js';
|
||||
import GeometryLayout from '../geom/GeometryLayout.js';
|
||||
@@ -24,370 +23,353 @@ import {quantizeMultiArray} from '../geom/flat/simplify.js';
|
||||
* @classdesc
|
||||
* Multi-polygon geometry.
|
||||
*
|
||||
* @constructor
|
||||
* @extends {module:ol/geom/SimpleGeometry}
|
||||
* @param {Array.<Array.<Array.<module:ol/coordinate~Coordinate>>>|Array.<number>} coordinates
|
||||
* Coordinates. (For internal use, flat coordinats in combination with
|
||||
* `opt_layout` and `opt_endss` are also accepted).
|
||||
* @param {module:ol/geom/GeometryLayout=} opt_layout Layout.
|
||||
* @param {Array.<number>} opt_endss Array of ends for internal use with flat
|
||||
* coordinates.
|
||||
* @api
|
||||
*/
|
||||
const MultiPolygon = function(coordinates, opt_layout, opt_endss) {
|
||||
|
||||
SimpleGeometry.call(this);
|
||||
class MultiPolygon extends SimpleGeometry {
|
||||
|
||||
/**
|
||||
* @type {Array.<Array.<number>>}
|
||||
* @private
|
||||
* @param {Array.<Array.<Array.<module:ol/coordinate~Coordinate>>>|Array.<number>} coordinates Coordinates.
|
||||
* For internal use, flat coordinats in combination with `opt_layout` and `opt_endss` are also accepted.
|
||||
* @param {module:ol/geom/GeometryLayout=} opt_layout Layout.
|
||||
* @param {Array.<number>} opt_endss Array of ends for internal use with flat coordinates.
|
||||
*/
|
||||
this.endss_ = [];
|
||||
constructor(coordinates, opt_layout, opt_endss) {
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {number}
|
||||
*/
|
||||
this.flatInteriorPointsRevision_ = -1;
|
||||
super();
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {Array.<number>}
|
||||
*/
|
||||
this.flatInteriorPoints_ = null;
|
||||
/**
|
||||
* @type {Array.<Array.<number>>}
|
||||
* @private
|
||||
*/
|
||||
this.endss_ = [];
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {number}
|
||||
*/
|
||||
this.maxDelta_ = -1;
|
||||
/**
|
||||
* @private
|
||||
* @type {number}
|
||||
*/
|
||||
this.flatInteriorPointsRevision_ = -1;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {number}
|
||||
*/
|
||||
this.maxDeltaRevision_ = -1;
|
||||
/**
|
||||
* @private
|
||||
* @type {Array.<number>}
|
||||
*/
|
||||
this.flatInteriorPoints_ = null;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {number}
|
||||
*/
|
||||
this.orientedRevision_ = -1;
|
||||
/**
|
||||
* @private
|
||||
* @type {number}
|
||||
*/
|
||||
this.maxDelta_ = -1;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {Array.<number>}
|
||||
*/
|
||||
this.orientedFlatCoordinates_ = null;
|
||||
/**
|
||||
* @private
|
||||
* @type {number}
|
||||
*/
|
||||
this.maxDeltaRevision_ = -1;
|
||||
|
||||
if (!opt_endss && !Array.isArray(coordinates[0])) {
|
||||
let layout = this.getLayout();
|
||||
const flatCoordinates = [];
|
||||
const endss = [];
|
||||
for (let i = 0, ii = coordinates.length; i < ii; ++i) {
|
||||
const polygon = coordinates[i];
|
||||
if (i === 0) {
|
||||
layout = polygon.getLayout();
|
||||
/**
|
||||
* @private
|
||||
* @type {number}
|
||||
*/
|
||||
this.orientedRevision_ = -1;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {Array.<number>}
|
||||
*/
|
||||
this.orientedFlatCoordinates_ = null;
|
||||
|
||||
if (!opt_endss && !Array.isArray(coordinates[0])) {
|
||||
let layout = this.getLayout();
|
||||
const flatCoordinates = [];
|
||||
const endss = [];
|
||||
for (let i = 0, ii = coordinates.length; i < ii; ++i) {
|
||||
const polygon = coordinates[i];
|
||||
if (i === 0) {
|
||||
layout = polygon.getLayout();
|
||||
}
|
||||
const offset = flatCoordinates.length;
|
||||
const ends = polygon.getEnds();
|
||||
for (let j = 0, jj = ends.length; j < jj; ++j) {
|
||||
ends[j] += offset;
|
||||
}
|
||||
extend(flatCoordinates, polygon.getFlatCoordinates());
|
||||
endss.push(ends);
|
||||
}
|
||||
const offset = flatCoordinates.length;
|
||||
const ends = polygon.getEnds();
|
||||
for (let j = 0, jj = ends.length; j < jj; ++j) {
|
||||
ends[j] += offset;
|
||||
}
|
||||
extend(flatCoordinates, polygon.getFlatCoordinates());
|
||||
endss.push(ends);
|
||||
opt_layout = layout;
|
||||
coordinates = flatCoordinates;
|
||||
opt_endss = endss;
|
||||
}
|
||||
opt_layout = layout;
|
||||
coordinates = flatCoordinates;
|
||||
opt_endss = endss;
|
||||
}
|
||||
if (opt_layout !== undefined && opt_endss) {
|
||||
this.setFlatCoordinates(opt_layout, coordinates);
|
||||
this.endss_ = opt_endss;
|
||||
} else {
|
||||
this.setCoordinates(coordinates, opt_layout);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
inherits(MultiPolygon, SimpleGeometry);
|
||||
|
||||
|
||||
/**
|
||||
* Append the passed polygon to this multipolygon.
|
||||
* @param {module:ol/geom/Polygon} polygon Polygon.
|
||||
* @api
|
||||
*/
|
||||
MultiPolygon.prototype.appendPolygon = function(polygon) {
|
||||
/** @type {Array.<number>} */
|
||||
let ends;
|
||||
if (!this.flatCoordinates) {
|
||||
this.flatCoordinates = polygon.getFlatCoordinates().slice();
|
||||
ends = polygon.getEnds().slice();
|
||||
this.endss_.push();
|
||||
} else {
|
||||
const offset = this.flatCoordinates.length;
|
||||
extend(this.flatCoordinates, polygon.getFlatCoordinates());
|
||||
ends = polygon.getEnds().slice();
|
||||
for (let i = 0, ii = ends.length; i < ii; ++i) {
|
||||
ends[i] += offset;
|
||||
}
|
||||
}
|
||||
this.endss_.push(ends);
|
||||
this.changed();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Make a complete copy of the geometry.
|
||||
* @return {!module:ol/geom/MultiPolygon} Clone.
|
||||
* @override
|
||||
* @api
|
||||
*/
|
||||
MultiPolygon.prototype.clone = function() {
|
||||
const len = this.endss_.length;
|
||||
const newEndss = new Array(len);
|
||||
for (let i = 0; i < len; ++i) {
|
||||
newEndss[i] = this.endss_[i].slice();
|
||||
}
|
||||
|
||||
return new MultiPolygon(
|
||||
this.flatCoordinates.slice(), this.layout, newEndss);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
MultiPolygon.prototype.closestPointXY = function(x, y, closestPoint, minSquaredDistance) {
|
||||
if (minSquaredDistance < closestSquaredDistanceXY(this.getExtent(), x, y)) {
|
||||
return minSquaredDistance;
|
||||
}
|
||||
if (this.maxDeltaRevision_ != this.getRevision()) {
|
||||
this.maxDelta_ = Math.sqrt(multiArrayMaxSquaredDelta(
|
||||
this.flatCoordinates, 0, this.endss_, this.stride, 0));
|
||||
this.maxDeltaRevision_ = this.getRevision();
|
||||
}
|
||||
return assignClosestMultiArrayPoint(
|
||||
this.getOrientedFlatCoordinates(), 0, this.endss_, this.stride,
|
||||
this.maxDelta_, true, x, y, closestPoint, minSquaredDistance);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
MultiPolygon.prototype.containsXY = function(x, y) {
|
||||
return linearRingssContainsXY(this.getOrientedFlatCoordinates(), 0, this.endss_, this.stride, x, y);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Return the area of the multipolygon on projected plane.
|
||||
* @return {number} Area (on projected plane).
|
||||
* @api
|
||||
*/
|
||||
MultiPolygon.prototype.getArea = function() {
|
||||
return linearRingssArea(this.getOrientedFlatCoordinates(), 0, this.endss_, this.stride);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get the coordinate array for this geometry. This array has the structure
|
||||
* of a GeoJSON coordinate array for multi-polygons.
|
||||
*
|
||||
* @param {boolean=} opt_right Orient coordinates according to the right-hand
|
||||
* rule (counter-clockwise for exterior and clockwise for interior rings).
|
||||
* If `false`, coordinates will be oriented according to the left-hand rule
|
||||
* (clockwise for exterior and counter-clockwise for interior rings).
|
||||
* By default, coordinate orientation will depend on how the geometry was
|
||||
* constructed.
|
||||
* @return {Array.<Array.<Array.<module:ol/coordinate~Coordinate>>>} Coordinates.
|
||||
* @override
|
||||
* @api
|
||||
*/
|
||||
MultiPolygon.prototype.getCoordinates = function(opt_right) {
|
||||
let flatCoordinates;
|
||||
if (opt_right !== undefined) {
|
||||
flatCoordinates = this.getOrientedFlatCoordinates().slice();
|
||||
orientLinearRingsArray(
|
||||
flatCoordinates, 0, this.endss_, this.stride, opt_right);
|
||||
} else {
|
||||
flatCoordinates = this.flatCoordinates;
|
||||
}
|
||||
|
||||
return inflateMultiCoordinatesArray(
|
||||
flatCoordinates, 0, this.endss_, this.stride);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {Array.<Array.<number>>} Endss.
|
||||
*/
|
||||
MultiPolygon.prototype.getEndss = function() {
|
||||
return this.endss_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {Array.<number>} Flat interior points.
|
||||
*/
|
||||
MultiPolygon.prototype.getFlatInteriorPoints = function() {
|
||||
if (this.flatInteriorPointsRevision_ != this.getRevision()) {
|
||||
const flatCenters = linearRingssCenter(
|
||||
this.flatCoordinates, 0, this.endss_, this.stride);
|
||||
this.flatInteriorPoints_ = getInteriorPointsOfMultiArray(
|
||||
this.getOrientedFlatCoordinates(), 0, this.endss_, this.stride,
|
||||
flatCenters);
|
||||
this.flatInteriorPointsRevision_ = this.getRevision();
|
||||
}
|
||||
return this.flatInteriorPoints_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Return the interior points as {@link module:ol/geom/MultiPoint multipoint}.
|
||||
* @return {module:ol/geom/MultiPoint} Interior points as XYM coordinates, where M is
|
||||
* the length of the horizontal intersection that the point belongs to.
|
||||
* @api
|
||||
*/
|
||||
MultiPolygon.prototype.getInteriorPoints = function() {
|
||||
return new MultiPoint(this.getFlatInteriorPoints().slice(), GeometryLayout.XYM);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {Array.<number>} Oriented flat coordinates.
|
||||
*/
|
||||
MultiPolygon.prototype.getOrientedFlatCoordinates = function() {
|
||||
if (this.orientedRevision_ != this.getRevision()) {
|
||||
const flatCoordinates = this.flatCoordinates;
|
||||
if (linearRingsAreOriented(
|
||||
flatCoordinates, 0, this.endss_, this.stride)) {
|
||||
this.orientedFlatCoordinates_ = flatCoordinates;
|
||||
if (opt_layout !== undefined && opt_endss) {
|
||||
this.setFlatCoordinates(opt_layout, coordinates);
|
||||
this.endss_ = opt_endss;
|
||||
} else {
|
||||
this.orientedFlatCoordinates_ = flatCoordinates.slice();
|
||||
this.orientedFlatCoordinates_.length =
|
||||
orientLinearRingsArray(
|
||||
this.orientedFlatCoordinates_, 0, this.endss_, this.stride);
|
||||
this.setCoordinates(coordinates, opt_layout);
|
||||
}
|
||||
this.orientedRevision_ = this.getRevision();
|
||||
|
||||
}
|
||||
return this.orientedFlatCoordinates_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
MultiPolygon.prototype.getSimplifiedGeometryInternal = function(squaredTolerance) {
|
||||
const simplifiedFlatCoordinates = [];
|
||||
const simplifiedEndss = [];
|
||||
simplifiedFlatCoordinates.length = quantizeMultiArray(
|
||||
this.flatCoordinates, 0, this.endss_, this.stride,
|
||||
Math.sqrt(squaredTolerance),
|
||||
simplifiedFlatCoordinates, 0, simplifiedEndss);
|
||||
return new MultiPolygon(simplifiedFlatCoordinates, GeometryLayout.XY, simplifiedEndss);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Return the polygon at the specified index.
|
||||
* @param {number} index Index.
|
||||
* @return {module:ol/geom/Polygon} Polygon.
|
||||
* @api
|
||||
*/
|
||||
MultiPolygon.prototype.getPolygon = function(index) {
|
||||
if (index < 0 || this.endss_.length <= index) {
|
||||
return null;
|
||||
}
|
||||
let offset;
|
||||
if (index === 0) {
|
||||
offset = 0;
|
||||
} else {
|
||||
const prevEnds = this.endss_[index - 1];
|
||||
offset = prevEnds[prevEnds.length - 1];
|
||||
}
|
||||
const ends = this.endss_[index].slice();
|
||||
const end = ends[ends.length - 1];
|
||||
if (offset !== 0) {
|
||||
for (let i = 0, ii = ends.length; i < ii; ++i) {
|
||||
ends[i] -= offset;
|
||||
/**
|
||||
* Append the passed polygon to this multipolygon.
|
||||
* @param {module:ol/geom/Polygon} polygon Polygon.
|
||||
* @api
|
||||
*/
|
||||
appendPolygon(polygon) {
|
||||
/** @type {Array.<number>} */
|
||||
let ends;
|
||||
if (!this.flatCoordinates) {
|
||||
this.flatCoordinates = polygon.getFlatCoordinates().slice();
|
||||
ends = polygon.getEnds().slice();
|
||||
this.endss_.push();
|
||||
} else {
|
||||
const offset = this.flatCoordinates.length;
|
||||
extend(this.flatCoordinates, polygon.getFlatCoordinates());
|
||||
ends = polygon.getEnds().slice();
|
||||
for (let i = 0, ii = ends.length; i < ii; ++i) {
|
||||
ends[i] += offset;
|
||||
}
|
||||
}
|
||||
this.endss_.push(ends);
|
||||
this.changed();
|
||||
}
|
||||
return new Polygon(this.flatCoordinates.slice(offset, end), this.layout, ends);
|
||||
};
|
||||
|
||||
/**
|
||||
* Make a complete copy of the geometry.
|
||||
* @return {!module:ol/geom/MultiPolygon} Clone.
|
||||
* @override
|
||||
* @api
|
||||
*/
|
||||
clone() {
|
||||
const len = this.endss_.length;
|
||||
const newEndss = new Array(len);
|
||||
for (let i = 0; i < len; ++i) {
|
||||
newEndss[i] = this.endss_[i].slice();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the polygons of this multipolygon.
|
||||
* @return {Array.<module:ol/geom/Polygon>} Polygons.
|
||||
* @api
|
||||
*/
|
||||
MultiPolygon.prototype.getPolygons = function() {
|
||||
const layout = this.layout;
|
||||
const flatCoordinates = this.flatCoordinates;
|
||||
const endss = this.endss_;
|
||||
const polygons = [];
|
||||
let offset = 0;
|
||||
for (let i = 0, ii = endss.length; i < ii; ++i) {
|
||||
const ends = endss[i].slice();
|
||||
return new MultiPolygon(
|
||||
this.flatCoordinates.slice(), this.layout, newEndss);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
closestPointXY(x, y, closestPoint, minSquaredDistance) {
|
||||
if (minSquaredDistance < closestSquaredDistanceXY(this.getExtent(), x, y)) {
|
||||
return minSquaredDistance;
|
||||
}
|
||||
if (this.maxDeltaRevision_ != this.getRevision()) {
|
||||
this.maxDelta_ = Math.sqrt(multiArrayMaxSquaredDelta(
|
||||
this.flatCoordinates, 0, this.endss_, this.stride, 0));
|
||||
this.maxDeltaRevision_ = this.getRevision();
|
||||
}
|
||||
return assignClosestMultiArrayPoint(
|
||||
this.getOrientedFlatCoordinates(), 0, this.endss_, this.stride,
|
||||
this.maxDelta_, true, x, y, closestPoint, minSquaredDistance);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
containsXY(x, y) {
|
||||
return linearRingssContainsXY(this.getOrientedFlatCoordinates(), 0, this.endss_, this.stride, x, y);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the area of the multipolygon on projected plane.
|
||||
* @return {number} Area (on projected plane).
|
||||
* @api
|
||||
*/
|
||||
getArea() {
|
||||
return linearRingssArea(this.getOrientedFlatCoordinates(), 0, this.endss_, this.stride);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the coordinate array for this geometry. This array has the structure
|
||||
* of a GeoJSON coordinate array for multi-polygons.
|
||||
*
|
||||
* @param {boolean=} opt_right Orient coordinates according to the right-hand
|
||||
* rule (counter-clockwise for exterior and clockwise for interior rings).
|
||||
* If `false`, coordinates will be oriented according to the left-hand rule
|
||||
* (clockwise for exterior and counter-clockwise for interior rings).
|
||||
* By default, coordinate orientation will depend on how the geometry was
|
||||
* constructed.
|
||||
* @return {Array.<Array.<Array.<module:ol/coordinate~Coordinate>>>} Coordinates.
|
||||
* @override
|
||||
* @api
|
||||
*/
|
||||
getCoordinates(opt_right) {
|
||||
let flatCoordinates;
|
||||
if (opt_right !== undefined) {
|
||||
flatCoordinates = this.getOrientedFlatCoordinates().slice();
|
||||
orientLinearRingsArray(
|
||||
flatCoordinates, 0, this.endss_, this.stride, opt_right);
|
||||
} else {
|
||||
flatCoordinates = this.flatCoordinates;
|
||||
}
|
||||
|
||||
return inflateMultiCoordinatesArray(
|
||||
flatCoordinates, 0, this.endss_, this.stride);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {Array.<Array.<number>>} Endss.
|
||||
*/
|
||||
getEndss() {
|
||||
return this.endss_;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {Array.<number>} Flat interior points.
|
||||
*/
|
||||
getFlatInteriorPoints() {
|
||||
if (this.flatInteriorPointsRevision_ != this.getRevision()) {
|
||||
const flatCenters = linearRingssCenter(
|
||||
this.flatCoordinates, 0, this.endss_, this.stride);
|
||||
this.flatInteriorPoints_ = getInteriorPointsOfMultiArray(
|
||||
this.getOrientedFlatCoordinates(), 0, this.endss_, this.stride,
|
||||
flatCenters);
|
||||
this.flatInteriorPointsRevision_ = this.getRevision();
|
||||
}
|
||||
return this.flatInteriorPoints_;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the interior points as {@link module:ol/geom/MultiPoint multipoint}.
|
||||
* @return {module:ol/geom/MultiPoint} Interior points as XYM coordinates, where M is
|
||||
* the length of the horizontal intersection that the point belongs to.
|
||||
* @api
|
||||
*/
|
||||
getInteriorPoints() {
|
||||
return new MultiPoint(this.getFlatInteriorPoints().slice(), GeometryLayout.XYM);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {Array.<number>} Oriented flat coordinates.
|
||||
*/
|
||||
getOrientedFlatCoordinates() {
|
||||
if (this.orientedRevision_ != this.getRevision()) {
|
||||
const flatCoordinates = this.flatCoordinates;
|
||||
if (linearRingsAreOriented(
|
||||
flatCoordinates, 0, this.endss_, this.stride)) {
|
||||
this.orientedFlatCoordinates_ = flatCoordinates;
|
||||
} else {
|
||||
this.orientedFlatCoordinates_ = flatCoordinates.slice();
|
||||
this.orientedFlatCoordinates_.length =
|
||||
orientLinearRingsArray(
|
||||
this.orientedFlatCoordinates_, 0, this.endss_, this.stride);
|
||||
}
|
||||
this.orientedRevision_ = this.getRevision();
|
||||
}
|
||||
return this.orientedFlatCoordinates_;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
getSimplifiedGeometryInternal(squaredTolerance) {
|
||||
const simplifiedFlatCoordinates = [];
|
||||
const simplifiedEndss = [];
|
||||
simplifiedFlatCoordinates.length = quantizeMultiArray(
|
||||
this.flatCoordinates, 0, this.endss_, this.stride,
|
||||
Math.sqrt(squaredTolerance),
|
||||
simplifiedFlatCoordinates, 0, simplifiedEndss);
|
||||
return new MultiPolygon(simplifiedFlatCoordinates, GeometryLayout.XY, simplifiedEndss);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the polygon at the specified index.
|
||||
* @param {number} index Index.
|
||||
* @return {module:ol/geom/Polygon} Polygon.
|
||||
* @api
|
||||
*/
|
||||
getPolygon(index) {
|
||||
if (index < 0 || this.endss_.length <= index) {
|
||||
return null;
|
||||
}
|
||||
let offset;
|
||||
if (index === 0) {
|
||||
offset = 0;
|
||||
} else {
|
||||
const prevEnds = this.endss_[index - 1];
|
||||
offset = prevEnds[prevEnds.length - 1];
|
||||
}
|
||||
const ends = this.endss_[index].slice();
|
||||
const end = ends[ends.length - 1];
|
||||
if (offset !== 0) {
|
||||
for (let j = 0, jj = ends.length; j < jj; ++j) {
|
||||
ends[j] -= offset;
|
||||
for (let i = 0, ii = ends.length; i < ii; ++i) {
|
||||
ends[i] -= offset;
|
||||
}
|
||||
}
|
||||
const polygon = new Polygon(flatCoordinates.slice(offset, end), layout, ends);
|
||||
polygons.push(polygon);
|
||||
offset = end;
|
||||
return new Polygon(this.flatCoordinates.slice(offset, end), this.layout, ends);
|
||||
}
|
||||
return polygons;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @api
|
||||
*/
|
||||
MultiPolygon.prototype.getType = function() {
|
||||
return GeometryType.MULTI_POLYGON;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @api
|
||||
*/
|
||||
MultiPolygon.prototype.intersectsExtent = function(extent) {
|
||||
return intersectsLinearRingMultiArray(
|
||||
this.getOrientedFlatCoordinates(), 0, this.endss_, this.stride, extent);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Set the coordinates of the multipolygon.
|
||||
* @param {!Array.<Array.<Array.<module:ol/coordinate~Coordinate>>>} coordinates Coordinates.
|
||||
* @param {module:ol/geom/GeometryLayout=} opt_layout Layout.
|
||||
* @override
|
||||
* @api
|
||||
*/
|
||||
MultiPolygon.prototype.setCoordinates = function(coordinates, opt_layout) {
|
||||
this.setLayout(opt_layout, coordinates, 3);
|
||||
if (!this.flatCoordinates) {
|
||||
this.flatCoordinates = [];
|
||||
/**
|
||||
* Return the polygons of this multipolygon.
|
||||
* @return {Array.<module:ol/geom/Polygon>} Polygons.
|
||||
* @api
|
||||
*/
|
||||
getPolygons() {
|
||||
const layout = this.layout;
|
||||
const flatCoordinates = this.flatCoordinates;
|
||||
const endss = this.endss_;
|
||||
const polygons = [];
|
||||
let offset = 0;
|
||||
for (let i = 0, ii = endss.length; i < ii; ++i) {
|
||||
const ends = endss[i].slice();
|
||||
const end = ends[ends.length - 1];
|
||||
if (offset !== 0) {
|
||||
for (let j = 0, jj = ends.length; j < jj; ++j) {
|
||||
ends[j] -= offset;
|
||||
}
|
||||
}
|
||||
const polygon = new Polygon(flatCoordinates.slice(offset, end), layout, ends);
|
||||
polygons.push(polygon);
|
||||
offset = end;
|
||||
}
|
||||
return polygons;
|
||||
}
|
||||
const endss = deflateMultiCoordinatesArray(
|
||||
this.flatCoordinates, 0, coordinates, this.stride, this.endss_);
|
||||
if (endss.length === 0) {
|
||||
this.flatCoordinates.length = 0;
|
||||
} else {
|
||||
const lastEnds = endss[endss.length - 1];
|
||||
this.flatCoordinates.length = lastEnds.length === 0 ?
|
||||
0 : lastEnds[lastEnds.length - 1];
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @api
|
||||
*/
|
||||
getType() {
|
||||
return GeometryType.MULTI_POLYGON;
|
||||
}
|
||||
this.changed();
|
||||
};
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @api
|
||||
*/
|
||||
intersectsExtent(extent) {
|
||||
return intersectsLinearRingMultiArray(
|
||||
this.getOrientedFlatCoordinates(), 0, this.endss_, this.stride, extent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the coordinates of the multipolygon.
|
||||
* @param {!Array.<Array.<Array.<module:ol/coordinate~Coordinate>>>} coordinates Coordinates.
|
||||
* @param {module:ol/geom/GeometryLayout=} opt_layout Layout.
|
||||
* @override
|
||||
* @api
|
||||
*/
|
||||
setCoordinates(coordinates, opt_layout) {
|
||||
this.setLayout(opt_layout, coordinates, 3);
|
||||
if (!this.flatCoordinates) {
|
||||
this.flatCoordinates = [];
|
||||
}
|
||||
const endss = deflateMultiCoordinatesArray(
|
||||
this.flatCoordinates, 0, coordinates, this.stride, this.endss_);
|
||||
if (endss.length === 0) {
|
||||
this.flatCoordinates.length = 0;
|
||||
} else {
|
||||
const lastEnds = endss[endss.length - 1];
|
||||
this.flatCoordinates.length = lastEnds.length === 0 ?
|
||||
0 : lastEnds[lastEnds.length - 1];
|
||||
}
|
||||
this.changed();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export default MultiPolygon;
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
/**
|
||||
* @module ol/geom/Point
|
||||
*/
|
||||
import {inherits} from '../util.js';
|
||||
import {createOrUpdateFromCoordinate, containsXY} from '../extent.js';
|
||||
import GeometryType from '../geom/GeometryType.js';
|
||||
import SimpleGeometry from '../geom/SimpleGeometry.js';
|
||||
@@ -12,100 +11,95 @@ import {squaredDistance as squaredDx} from '../math.js';
|
||||
* @classdesc
|
||||
* Point geometry.
|
||||
*
|
||||
* @constructor
|
||||
* @extends {module:ol/geom/SimpleGeometry}
|
||||
* @param {module:ol/coordinate~Coordinate} coordinates Coordinates.
|
||||
* @param {module:ol/geom/GeometryLayout=} opt_layout Layout.
|
||||
* @api
|
||||
*/
|
||||
const Point = function(coordinates, opt_layout) {
|
||||
SimpleGeometry.call(this);
|
||||
this.setCoordinates(coordinates, opt_layout);
|
||||
};
|
||||
class Point extends SimpleGeometry {
|
||||
|
||||
inherits(Point, SimpleGeometry);
|
||||
/**
|
||||
* @param {module:ol/coordinate~Coordinate} coordinates Coordinates.
|
||||
* @param {module:ol/geom/GeometryLayout=} opt_layout Layout.
|
||||
*/
|
||||
constructor(coordinates, opt_layout) {
|
||||
super();
|
||||
this.setCoordinates(coordinates, opt_layout);
|
||||
}
|
||||
|
||||
/**
|
||||
* Make a complete copy of the geometry.
|
||||
* @return {!module:ol/geom/Point} Clone.
|
||||
* @override
|
||||
* @api
|
||||
*/
|
||||
clone() {
|
||||
const point = new Point(this.flatCoordinates.slice(), this.layout);
|
||||
return point;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make a complete copy of the geometry.
|
||||
* @return {!module:ol/geom/Point} Clone.
|
||||
* @override
|
||||
* @api
|
||||
*/
|
||||
Point.prototype.clone = function() {
|
||||
const point = new Point(this.flatCoordinates.slice(), this.layout);
|
||||
return point;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
Point.prototype.closestPointXY = function(x, y, closestPoint, minSquaredDistance) {
|
||||
const flatCoordinates = this.flatCoordinates;
|
||||
const squaredDistance = squaredDx(x, y, flatCoordinates[0], flatCoordinates[1]);
|
||||
if (squaredDistance < minSquaredDistance) {
|
||||
const stride = this.stride;
|
||||
for (let i = 0; i < stride; ++i) {
|
||||
closestPoint[i] = flatCoordinates[i];
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
closestPointXY(x, y, closestPoint, minSquaredDistance) {
|
||||
const flatCoordinates = this.flatCoordinates;
|
||||
const squaredDistance = squaredDx(x, y, flatCoordinates[0], flatCoordinates[1]);
|
||||
if (squaredDistance < minSquaredDistance) {
|
||||
const stride = this.stride;
|
||||
for (let i = 0; i < stride; ++i) {
|
||||
closestPoint[i] = flatCoordinates[i];
|
||||
}
|
||||
closestPoint.length = stride;
|
||||
return squaredDistance;
|
||||
} else {
|
||||
return minSquaredDistance;
|
||||
}
|
||||
closestPoint.length = stride;
|
||||
return squaredDistance;
|
||||
} else {
|
||||
return minSquaredDistance;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Return the coordinate of the point.
|
||||
* @return {module:ol/coordinate~Coordinate} Coordinates.
|
||||
* @override
|
||||
* @api
|
||||
*/
|
||||
Point.prototype.getCoordinates = function() {
|
||||
return !this.flatCoordinates ? [] : this.flatCoordinates.slice();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
Point.prototype.computeExtent = function(extent) {
|
||||
return createOrUpdateFromCoordinate(this.flatCoordinates, extent);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @api
|
||||
*/
|
||||
Point.prototype.getType = function() {
|
||||
return GeometryType.POINT;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @api
|
||||
*/
|
||||
Point.prototype.intersectsExtent = function(extent) {
|
||||
return containsXY(extent, this.flatCoordinates[0], this.flatCoordinates[1]);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @api
|
||||
*/
|
||||
Point.prototype.setCoordinates = function(coordinates, opt_layout) {
|
||||
this.setLayout(opt_layout, coordinates, 0);
|
||||
if (!this.flatCoordinates) {
|
||||
this.flatCoordinates = [];
|
||||
/**
|
||||
* Return the coordinate of the point.
|
||||
* @return {module:ol/coordinate~Coordinate} Coordinates.
|
||||
* @override
|
||||
* @api
|
||||
*/
|
||||
getCoordinates() {
|
||||
return !this.flatCoordinates ? [] : this.flatCoordinates.slice();
|
||||
}
|
||||
this.flatCoordinates.length = deflateCoordinate(
|
||||
this.flatCoordinates, 0, coordinates, this.stride);
|
||||
this.changed();
|
||||
};
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
computeExtent(extent) {
|
||||
return createOrUpdateFromCoordinate(this.flatCoordinates, extent);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @api
|
||||
*/
|
||||
getType() {
|
||||
return GeometryType.POINT;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @api
|
||||
*/
|
||||
intersectsExtent(extent) {
|
||||
return containsXY(extent, this.flatCoordinates[0], this.flatCoordinates[1]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @api
|
||||
*/
|
||||
setCoordinates(coordinates, opt_layout) {
|
||||
this.setLayout(opt_layout, coordinates, 0);
|
||||
if (!this.flatCoordinates) {
|
||||
this.flatCoordinates = [];
|
||||
}
|
||||
this.flatCoordinates.length = deflateCoordinate(
|
||||
this.flatCoordinates, 0, coordinates, this.stride);
|
||||
this.changed();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export default Point;
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
/**
|
||||
* @module ol/geom/Polygon
|
||||
*/
|
||||
import {inherits} from '../util.js';
|
||||
import {extend} from '../array.js';
|
||||
import {closestSquaredDistanceXY, getCenter} from '../extent.js';
|
||||
import GeometryLayout from '../geom/GeometryLayout.js';
|
||||
@@ -25,327 +24,311 @@ import {modulo} from '../math.js';
|
||||
* @classdesc
|
||||
* Polygon geometry.
|
||||
*
|
||||
* @constructor
|
||||
* @extends {module:ol/geom/SimpleGeometry}
|
||||
* @param {!Array.<Array.<module:ol/coordinate~Coordinate>>|!Array.<number>} coordinates
|
||||
* Array of linear rings that define the polygon. The first linear ring of the
|
||||
* array defines the outer-boundary or surface of the polygon. Each subsequent
|
||||
* linear ring defines a hole in the surface of the polygon. A linear ring is
|
||||
* an array of vertices' coordinates where the first coordinate and the last are
|
||||
* equivalent. (For internal use, flat coordinates in combination with
|
||||
* `opt_layout` and `opt_ends` are also accepted.)
|
||||
* @param {module:ol/geom/GeometryLayout=} opt_layout Layout.
|
||||
* @param {Array.<number>=} opt_ends Ends (for internal use with flat
|
||||
* coordinates).
|
||||
* @api
|
||||
*/
|
||||
const Polygon = function(coordinates, opt_layout, opt_ends) {
|
||||
|
||||
SimpleGeometry.call(this);
|
||||
class Polygon extends SimpleGeometry {
|
||||
|
||||
/**
|
||||
* @type {Array.<number>}
|
||||
* @private
|
||||
* @param {!Array.<Array.<module:ol/coordinate~Coordinate>>|!Array.<number>} coordinates
|
||||
* Array of linear rings that define the polygon. The first linear ring of the
|
||||
* array defines the outer-boundary or surface of the polygon. Each subsequent
|
||||
* linear ring defines a hole in the surface of the polygon. A linear ring is
|
||||
* an array of vertices' coordinates where the first coordinate and the last are
|
||||
* equivalent. (For internal use, flat coordinates in combination with
|
||||
* `opt_layout` and `opt_ends` are also accepted.)
|
||||
* @param {module:ol/geom/GeometryLayout=} opt_layout Layout.
|
||||
* @param {Array.<number>=} opt_ends Ends (for internal use with flat coordinates).
|
||||
*/
|
||||
this.ends_ = [];
|
||||
constructor(coordinates, opt_layout, opt_ends) {
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {number}
|
||||
*/
|
||||
this.flatInteriorPointRevision_ = -1;
|
||||
super();
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {module:ol/coordinate~Coordinate}
|
||||
*/
|
||||
this.flatInteriorPoint_ = null;
|
||||
/**
|
||||
* @type {Array.<number>}
|
||||
* @private
|
||||
*/
|
||||
this.ends_ = [];
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {number}
|
||||
*/
|
||||
this.maxDelta_ = -1;
|
||||
/**
|
||||
* @private
|
||||
* @type {number}
|
||||
*/
|
||||
this.flatInteriorPointRevision_ = -1;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {number}
|
||||
*/
|
||||
this.maxDeltaRevision_ = -1;
|
||||
/**
|
||||
* @private
|
||||
* @type {module:ol/coordinate~Coordinate}
|
||||
*/
|
||||
this.flatInteriorPoint_ = null;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {number}
|
||||
*/
|
||||
this.orientedRevision_ = -1;
|
||||
/**
|
||||
* @private
|
||||
* @type {number}
|
||||
*/
|
||||
this.maxDelta_ = -1;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {Array.<number>}
|
||||
*/
|
||||
this.orientedFlatCoordinates_ = null;
|
||||
/**
|
||||
* @private
|
||||
* @type {number}
|
||||
*/
|
||||
this.maxDeltaRevision_ = -1;
|
||||
|
||||
if (opt_layout !== undefined && opt_ends) {
|
||||
this.setFlatCoordinates(opt_layout, coordinates);
|
||||
this.ends_ = opt_ends;
|
||||
} else {
|
||||
this.setCoordinates(coordinates, opt_layout);
|
||||
}
|
||||
/**
|
||||
* @private
|
||||
* @type {number}
|
||||
*/
|
||||
this.orientedRevision_ = -1;
|
||||
|
||||
};
|
||||
/**
|
||||
* @private
|
||||
* @type {Array.<number>}
|
||||
*/
|
||||
this.orientedFlatCoordinates_ = null;
|
||||
|
||||
inherits(Polygon, SimpleGeometry);
|
||||
|
||||
|
||||
/**
|
||||
* Append the passed linear ring to this polygon.
|
||||
* @param {module:ol/geom/LinearRing} linearRing Linear ring.
|
||||
* @api
|
||||
*/
|
||||
Polygon.prototype.appendLinearRing = function(linearRing) {
|
||||
if (!this.flatCoordinates) {
|
||||
this.flatCoordinates = linearRing.getFlatCoordinates().slice();
|
||||
} else {
|
||||
extend(this.flatCoordinates, linearRing.getFlatCoordinates());
|
||||
}
|
||||
this.ends_.push(this.flatCoordinates.length);
|
||||
this.changed();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Make a complete copy of the geometry.
|
||||
* @return {!module:ol/geom/Polygon} Clone.
|
||||
* @override
|
||||
* @api
|
||||
*/
|
||||
Polygon.prototype.clone = function() {
|
||||
return new Polygon(this.flatCoordinates.slice(), this.layout, this.ends_.slice());
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
Polygon.prototype.closestPointXY = function(x, y, closestPoint, minSquaredDistance) {
|
||||
if (minSquaredDistance < closestSquaredDistanceXY(this.getExtent(), x, y)) {
|
||||
return minSquaredDistance;
|
||||
}
|
||||
if (this.maxDeltaRevision_ != this.getRevision()) {
|
||||
this.maxDelta_ = Math.sqrt(arrayMaxSquaredDelta(
|
||||
this.flatCoordinates, 0, this.ends_, this.stride, 0));
|
||||
this.maxDeltaRevision_ = this.getRevision();
|
||||
}
|
||||
return assignClosestArrayPoint(
|
||||
this.flatCoordinates, 0, this.ends_, this.stride,
|
||||
this.maxDelta_, true, x, y, closestPoint, minSquaredDistance);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
Polygon.prototype.containsXY = function(x, y) {
|
||||
return linearRingsContainsXY(this.getOrientedFlatCoordinates(), 0, this.ends_, this.stride, x, y);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Return the area of the polygon on projected plane.
|
||||
* @return {number} Area (on projected plane).
|
||||
* @api
|
||||
*/
|
||||
Polygon.prototype.getArea = function() {
|
||||
return linearRingsArea(this.getOrientedFlatCoordinates(), 0, this.ends_, this.stride);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get the coordinate array for this geometry. This array has the structure
|
||||
* of a GeoJSON coordinate array for polygons.
|
||||
*
|
||||
* @param {boolean=} opt_right Orient coordinates according to the right-hand
|
||||
* rule (counter-clockwise for exterior and clockwise for interior rings).
|
||||
* If `false`, coordinates will be oriented according to the left-hand rule
|
||||
* (clockwise for exterior and counter-clockwise for interior rings).
|
||||
* By default, coordinate orientation will depend on how the geometry was
|
||||
* constructed.
|
||||
* @return {Array.<Array.<module:ol/coordinate~Coordinate>>} Coordinates.
|
||||
* @override
|
||||
* @api
|
||||
*/
|
||||
Polygon.prototype.getCoordinates = function(opt_right) {
|
||||
let flatCoordinates;
|
||||
if (opt_right !== undefined) {
|
||||
flatCoordinates = this.getOrientedFlatCoordinates().slice();
|
||||
orientLinearRings(
|
||||
flatCoordinates, 0, this.ends_, this.stride, opt_right);
|
||||
} else {
|
||||
flatCoordinates = this.flatCoordinates;
|
||||
}
|
||||
|
||||
return inflateCoordinatesArray(
|
||||
flatCoordinates, 0, this.ends_, this.stride);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {Array.<number>} Ends.
|
||||
*/
|
||||
Polygon.prototype.getEnds = function() {
|
||||
return this.ends_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {Array.<number>} Interior point.
|
||||
*/
|
||||
Polygon.prototype.getFlatInteriorPoint = function() {
|
||||
if (this.flatInteriorPointRevision_ != this.getRevision()) {
|
||||
const flatCenter = getCenter(this.getExtent());
|
||||
this.flatInteriorPoint_ = getInteriorPointOfArray(
|
||||
this.getOrientedFlatCoordinates(), 0, this.ends_, this.stride,
|
||||
flatCenter, 0);
|
||||
this.flatInteriorPointRevision_ = this.getRevision();
|
||||
}
|
||||
return this.flatInteriorPoint_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Return an interior point of the polygon.
|
||||
* @return {module:ol/geom/Point} Interior point as XYM coordinate, where M is the
|
||||
* length of the horizontal intersection that the point belongs to.
|
||||
* @api
|
||||
*/
|
||||
Polygon.prototype.getInteriorPoint = function() {
|
||||
return new Point(this.getFlatInteriorPoint(), GeometryLayout.XYM);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Return the number of rings of the polygon, this includes the exterior
|
||||
* ring and any interior rings.
|
||||
*
|
||||
* @return {number} Number of rings.
|
||||
* @api
|
||||
*/
|
||||
Polygon.prototype.getLinearRingCount = function() {
|
||||
return this.ends_.length;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Return the Nth linear ring of the polygon geometry. Return `null` if the
|
||||
* given index is out of range.
|
||||
* The exterior linear ring is available at index `0` and the interior rings
|
||||
* at index `1` and beyond.
|
||||
*
|
||||
* @param {number} index Index.
|
||||
* @return {module:ol/geom/LinearRing} Linear ring.
|
||||
* @api
|
||||
*/
|
||||
Polygon.prototype.getLinearRing = function(index) {
|
||||
if (index < 0 || this.ends_.length <= index) {
|
||||
return null;
|
||||
}
|
||||
return new LinearRing(this.flatCoordinates.slice(
|
||||
index === 0 ? 0 : this.ends_[index - 1], this.ends_[index]), this.layout);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Return the linear rings of the polygon.
|
||||
* @return {Array.<module:ol/geom/LinearRing>} Linear rings.
|
||||
* @api
|
||||
*/
|
||||
Polygon.prototype.getLinearRings = function() {
|
||||
const layout = this.layout;
|
||||
const flatCoordinates = this.flatCoordinates;
|
||||
const ends = this.ends_;
|
||||
const linearRings = [];
|
||||
let offset = 0;
|
||||
for (let i = 0, ii = ends.length; i < ii; ++i) {
|
||||
const end = ends[i];
|
||||
const linearRing = new LinearRing(flatCoordinates.slice(offset, end), layout);
|
||||
linearRings.push(linearRing);
|
||||
offset = end;
|
||||
}
|
||||
return linearRings;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {Array.<number>} Oriented flat coordinates.
|
||||
*/
|
||||
Polygon.prototype.getOrientedFlatCoordinates = function() {
|
||||
if (this.orientedRevision_ != this.getRevision()) {
|
||||
const flatCoordinates = this.flatCoordinates;
|
||||
if (linearRingIsOriented(
|
||||
flatCoordinates, 0, this.ends_, this.stride)) {
|
||||
this.orientedFlatCoordinates_ = flatCoordinates;
|
||||
if (opt_layout !== undefined && opt_ends) {
|
||||
this.setFlatCoordinates(opt_layout, coordinates);
|
||||
this.ends_ = opt_ends;
|
||||
} else {
|
||||
this.orientedFlatCoordinates_ = flatCoordinates.slice();
|
||||
this.orientedFlatCoordinates_.length =
|
||||
orientLinearRings(
|
||||
this.orientedFlatCoordinates_, 0, this.ends_, this.stride);
|
||||
this.setCoordinates(coordinates, opt_layout);
|
||||
}
|
||||
this.orientedRevision_ = this.getRevision();
|
||||
|
||||
}
|
||||
return this.orientedFlatCoordinates_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
Polygon.prototype.getSimplifiedGeometryInternal = function(squaredTolerance) {
|
||||
const simplifiedFlatCoordinates = [];
|
||||
const simplifiedEnds = [];
|
||||
simplifiedFlatCoordinates.length = quantizeArray(
|
||||
this.flatCoordinates, 0, this.ends_, this.stride,
|
||||
Math.sqrt(squaredTolerance),
|
||||
simplifiedFlatCoordinates, 0, simplifiedEnds);
|
||||
return new Polygon(simplifiedFlatCoordinates, GeometryLayout.XY, simplifiedEnds);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @api
|
||||
*/
|
||||
Polygon.prototype.getType = function() {
|
||||
return GeometryType.POLYGON;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @api
|
||||
*/
|
||||
Polygon.prototype.intersectsExtent = function(extent) {
|
||||
return intersectsLinearRingArray(
|
||||
this.getOrientedFlatCoordinates(), 0, this.ends_, this.stride, extent);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Set the coordinates of the polygon.
|
||||
* @param {!Array.<Array.<module:ol/coordinate~Coordinate>>} coordinates Coordinates.
|
||||
* @param {module:ol/geom/GeometryLayout=} opt_layout Layout.
|
||||
* @override
|
||||
* @api
|
||||
*/
|
||||
Polygon.prototype.setCoordinates = function(coordinates, opt_layout) {
|
||||
this.setLayout(opt_layout, coordinates, 2);
|
||||
if (!this.flatCoordinates) {
|
||||
this.flatCoordinates = [];
|
||||
/**
|
||||
* Append the passed linear ring to this polygon.
|
||||
* @param {module:ol/geom/LinearRing} linearRing Linear ring.
|
||||
* @api
|
||||
*/
|
||||
appendLinearRing(linearRing) {
|
||||
if (!this.flatCoordinates) {
|
||||
this.flatCoordinates = linearRing.getFlatCoordinates().slice();
|
||||
} else {
|
||||
extend(this.flatCoordinates, linearRing.getFlatCoordinates());
|
||||
}
|
||||
this.ends_.push(this.flatCoordinates.length);
|
||||
this.changed();
|
||||
}
|
||||
const ends = deflateCoordinatesArray(
|
||||
this.flatCoordinates, 0, coordinates, this.stride, this.ends_);
|
||||
this.flatCoordinates.length = ends.length === 0 ? 0 : ends[ends.length - 1];
|
||||
this.changed();
|
||||
};
|
||||
|
||||
/**
|
||||
* Make a complete copy of the geometry.
|
||||
* @return {!module:ol/geom/Polygon} Clone.
|
||||
* @override
|
||||
* @api
|
||||
*/
|
||||
clone() {
|
||||
return new Polygon(this.flatCoordinates.slice(), this.layout, this.ends_.slice());
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
closestPointXY(x, y, closestPoint, minSquaredDistance) {
|
||||
if (minSquaredDistance < closestSquaredDistanceXY(this.getExtent(), x, y)) {
|
||||
return minSquaredDistance;
|
||||
}
|
||||
if (this.maxDeltaRevision_ != this.getRevision()) {
|
||||
this.maxDelta_ = Math.sqrt(arrayMaxSquaredDelta(
|
||||
this.flatCoordinates, 0, this.ends_, this.stride, 0));
|
||||
this.maxDeltaRevision_ = this.getRevision();
|
||||
}
|
||||
return assignClosestArrayPoint(
|
||||
this.flatCoordinates, 0, this.ends_, this.stride,
|
||||
this.maxDelta_, true, x, y, closestPoint, minSquaredDistance);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
containsXY(x, y) {
|
||||
return linearRingsContainsXY(this.getOrientedFlatCoordinates(), 0, this.ends_, this.stride, x, y);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the area of the polygon on projected plane.
|
||||
* @return {number} Area (on projected plane).
|
||||
* @api
|
||||
*/
|
||||
getArea() {
|
||||
return linearRingsArea(this.getOrientedFlatCoordinates(), 0, this.ends_, this.stride);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the coordinate array for this geometry. This array has the structure
|
||||
* of a GeoJSON coordinate array for polygons.
|
||||
*
|
||||
* @param {boolean=} opt_right Orient coordinates according to the right-hand
|
||||
* rule (counter-clockwise for exterior and clockwise for interior rings).
|
||||
* If `false`, coordinates will be oriented according to the left-hand rule
|
||||
* (clockwise for exterior and counter-clockwise for interior rings).
|
||||
* By default, coordinate orientation will depend on how the geometry was
|
||||
* constructed.
|
||||
* @return {Array.<Array.<module:ol/coordinate~Coordinate>>} Coordinates.
|
||||
* @override
|
||||
* @api
|
||||
*/
|
||||
getCoordinates(opt_right) {
|
||||
let flatCoordinates;
|
||||
if (opt_right !== undefined) {
|
||||
flatCoordinates = this.getOrientedFlatCoordinates().slice();
|
||||
orientLinearRings(
|
||||
flatCoordinates, 0, this.ends_, this.stride, opt_right);
|
||||
} else {
|
||||
flatCoordinates = this.flatCoordinates;
|
||||
}
|
||||
|
||||
return inflateCoordinatesArray(
|
||||
flatCoordinates, 0, this.ends_, this.stride);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {Array.<number>} Ends.
|
||||
*/
|
||||
getEnds() {
|
||||
return this.ends_;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {Array.<number>} Interior point.
|
||||
*/
|
||||
getFlatInteriorPoint() {
|
||||
if (this.flatInteriorPointRevision_ != this.getRevision()) {
|
||||
const flatCenter = getCenter(this.getExtent());
|
||||
this.flatInteriorPoint_ = getInteriorPointOfArray(
|
||||
this.getOrientedFlatCoordinates(), 0, this.ends_, this.stride,
|
||||
flatCenter, 0);
|
||||
this.flatInteriorPointRevision_ = this.getRevision();
|
||||
}
|
||||
return this.flatInteriorPoint_;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an interior point of the polygon.
|
||||
* @return {module:ol/geom/Point} Interior point as XYM coordinate, where M is the
|
||||
* length of the horizontal intersection that the point belongs to.
|
||||
* @api
|
||||
*/
|
||||
getInteriorPoint() {
|
||||
return new Point(this.getFlatInteriorPoint(), GeometryLayout.XYM);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the number of rings of the polygon, this includes the exterior
|
||||
* ring and any interior rings.
|
||||
*
|
||||
* @return {number} Number of rings.
|
||||
* @api
|
||||
*/
|
||||
getLinearRingCount() {
|
||||
return this.ends_.length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the Nth linear ring of the polygon geometry. Return `null` if the
|
||||
* given index is out of range.
|
||||
* The exterior linear ring is available at index `0` and the interior rings
|
||||
* at index `1` and beyond.
|
||||
*
|
||||
* @param {number} index Index.
|
||||
* @return {module:ol/geom/LinearRing} Linear ring.
|
||||
* @api
|
||||
*/
|
||||
getLinearRing(index) {
|
||||
if (index < 0 || this.ends_.length <= index) {
|
||||
return null;
|
||||
}
|
||||
return new LinearRing(this.flatCoordinates.slice(
|
||||
index === 0 ? 0 : this.ends_[index - 1], this.ends_[index]), this.layout);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the linear rings of the polygon.
|
||||
* @return {Array.<module:ol/geom/LinearRing>} Linear rings.
|
||||
* @api
|
||||
*/
|
||||
getLinearRings() {
|
||||
const layout = this.layout;
|
||||
const flatCoordinates = this.flatCoordinates;
|
||||
const ends = this.ends_;
|
||||
const linearRings = [];
|
||||
let offset = 0;
|
||||
for (let i = 0, ii = ends.length; i < ii; ++i) {
|
||||
const end = ends[i];
|
||||
const linearRing = new LinearRing(flatCoordinates.slice(offset, end), layout);
|
||||
linearRings.push(linearRing);
|
||||
offset = end;
|
||||
}
|
||||
return linearRings;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {Array.<number>} Oriented flat coordinates.
|
||||
*/
|
||||
getOrientedFlatCoordinates() {
|
||||
if (this.orientedRevision_ != this.getRevision()) {
|
||||
const flatCoordinates = this.flatCoordinates;
|
||||
if (linearRingIsOriented(
|
||||
flatCoordinates, 0, this.ends_, this.stride)) {
|
||||
this.orientedFlatCoordinates_ = flatCoordinates;
|
||||
} else {
|
||||
this.orientedFlatCoordinates_ = flatCoordinates.slice();
|
||||
this.orientedFlatCoordinates_.length =
|
||||
orientLinearRings(
|
||||
this.orientedFlatCoordinates_, 0, this.ends_, this.stride);
|
||||
}
|
||||
this.orientedRevision_ = this.getRevision();
|
||||
}
|
||||
return this.orientedFlatCoordinates_;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
getSimplifiedGeometryInternal(squaredTolerance) {
|
||||
const simplifiedFlatCoordinates = [];
|
||||
const simplifiedEnds = [];
|
||||
simplifiedFlatCoordinates.length = quantizeArray(
|
||||
this.flatCoordinates, 0, this.ends_, this.stride,
|
||||
Math.sqrt(squaredTolerance),
|
||||
simplifiedFlatCoordinates, 0, simplifiedEnds);
|
||||
return new Polygon(simplifiedFlatCoordinates, GeometryLayout.XY, simplifiedEnds);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @api
|
||||
*/
|
||||
getType() {
|
||||
return GeometryType.POLYGON;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @api
|
||||
*/
|
||||
intersectsExtent(extent) {
|
||||
return intersectsLinearRingArray(
|
||||
this.getOrientedFlatCoordinates(), 0, this.ends_, this.stride, extent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the coordinates of the polygon.
|
||||
* @param {!Array.<Array.<module:ol/coordinate~Coordinate>>} coordinates Coordinates.
|
||||
* @param {module:ol/geom/GeometryLayout=} opt_layout Layout.
|
||||
* @override
|
||||
* @api
|
||||
*/
|
||||
setCoordinates(coordinates, opt_layout) {
|
||||
this.setLayout(opt_layout, coordinates, 2);
|
||||
if (!this.flatCoordinates) {
|
||||
this.flatCoordinates = [];
|
||||
}
|
||||
const ends = deflateCoordinatesArray(
|
||||
this.flatCoordinates, 0, coordinates, this.stride, this.ends_);
|
||||
this.flatCoordinates.length = ends.length === 0 ? 0 : ends[ends.length - 1];
|
||||
this.changed();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export default Polygon;
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
/**
|
||||
* @module ol/geom/SimpleGeometry
|
||||
*/
|
||||
import {inherits} from '../util.js';
|
||||
import {FALSE} from '../functions.js';
|
||||
import {createOrUpdateFromFlatCoordinates, getCenter} from '../extent.js';
|
||||
import Geometry from '../geom/Geometry.js';
|
||||
@@ -14,36 +13,246 @@ import {clear} from '../obj.js';
|
||||
* Abstract base class; only used for creating subclasses; do not instantiate
|
||||
* in apps, as cannot be rendered.
|
||||
*
|
||||
* @constructor
|
||||
* @abstract
|
||||
* @extends {module:ol/geom/Geometry}
|
||||
* @api
|
||||
*/
|
||||
const SimpleGeometry = function() {
|
||||
class SimpleGeometry extends Geometry {
|
||||
constructor() {
|
||||
|
||||
Geometry.call(this);
|
||||
super();
|
||||
|
||||
/**
|
||||
* @protected
|
||||
* @type {module:ol/geom/GeometryLayout}
|
||||
*/
|
||||
this.layout = GeometryLayout.XY;
|
||||
|
||||
/**
|
||||
* @protected
|
||||
* @type {number}
|
||||
*/
|
||||
this.stride = 2;
|
||||
|
||||
/**
|
||||
* @protected
|
||||
* @type {Array.<number>}
|
||||
*/
|
||||
this.flatCoordinates = null;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @protected
|
||||
* @type {module:ol/geom/GeometryLayout}
|
||||
* @inheritDoc
|
||||
*/
|
||||
this.layout = GeometryLayout.XY;
|
||||
computeExtent(extent) {
|
||||
return createOrUpdateFromFlatCoordinates(this.flatCoordinates,
|
||||
0, this.flatCoordinates.length, this.stride, extent);
|
||||
}
|
||||
|
||||
/**
|
||||
* @protected
|
||||
* @type {number}
|
||||
* @abstract
|
||||
* @return {Array} Coordinates.
|
||||
*/
|
||||
this.stride = 2;
|
||||
getCoordinates() {}
|
||||
|
||||
/**
|
||||
* @protected
|
||||
* @type {Array.<number>}
|
||||
* Return the first coordinate of the geometry.
|
||||
* @return {module:ol/coordinate~Coordinate} First coordinate.
|
||||
* @api
|
||||
*/
|
||||
this.flatCoordinates = null;
|
||||
getFirstCoordinate() {
|
||||
return this.flatCoordinates.slice(0, this.stride);
|
||||
}
|
||||
|
||||
};
|
||||
/**
|
||||
* @return {Array.<number>} Flat coordinates.
|
||||
*/
|
||||
getFlatCoordinates() {
|
||||
return this.flatCoordinates;
|
||||
}
|
||||
|
||||
inherits(SimpleGeometry, Geometry);
|
||||
/**
|
||||
* Return the last coordinate of the geometry.
|
||||
* @return {module:ol/coordinate~Coordinate} Last point.
|
||||
* @api
|
||||
*/
|
||||
getLastCoordinate() {
|
||||
return this.flatCoordinates.slice(this.flatCoordinates.length - this.stride);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the {@link module:ol/geom/GeometryLayout~GeometryLayout layout} of the geometry.
|
||||
* @return {module:ol/geom/GeometryLayout} Layout.
|
||||
* @api
|
||||
*/
|
||||
getLayout() {
|
||||
return this.layout;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
getSimplifiedGeometry(squaredTolerance) {
|
||||
if (this.simplifiedGeometryRevision != this.getRevision()) {
|
||||
clear(this.simplifiedGeometryCache);
|
||||
this.simplifiedGeometryMaxMinSquaredTolerance = 0;
|
||||
this.simplifiedGeometryRevision = this.getRevision();
|
||||
}
|
||||
// If squaredTolerance is negative or if we know that simplification will not
|
||||
// have any effect then just return this.
|
||||
if (squaredTolerance < 0 ||
|
||||
(this.simplifiedGeometryMaxMinSquaredTolerance !== 0 &&
|
||||
squaredTolerance <= this.simplifiedGeometryMaxMinSquaredTolerance)) {
|
||||
return this;
|
||||
}
|
||||
const key = squaredTolerance.toString();
|
||||
if (this.simplifiedGeometryCache.hasOwnProperty(key)) {
|
||||
return this.simplifiedGeometryCache[key];
|
||||
} else {
|
||||
const simplifiedGeometry =
|
||||
this.getSimplifiedGeometryInternal(squaredTolerance);
|
||||
const simplifiedFlatCoordinates = simplifiedGeometry.getFlatCoordinates();
|
||||
if (simplifiedFlatCoordinates.length < this.flatCoordinates.length) {
|
||||
this.simplifiedGeometryCache[key] = simplifiedGeometry;
|
||||
return simplifiedGeometry;
|
||||
} else {
|
||||
// Simplification did not actually remove any coordinates. We now know
|
||||
// that any calls to getSimplifiedGeometry with a squaredTolerance less
|
||||
// than or equal to the current squaredTolerance will also not have any
|
||||
// effect. This allows us to short circuit simplification (saving CPU
|
||||
// cycles) and prevents the cache of simplified geometries from filling
|
||||
// up with useless identical copies of this geometry (saving memory).
|
||||
this.simplifiedGeometryMaxMinSquaredTolerance = squaredTolerance;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {number} squaredTolerance Squared tolerance.
|
||||
* @return {module:ol/geom/SimpleGeometry} Simplified geometry.
|
||||
* @protected
|
||||
*/
|
||||
getSimplifiedGeometryInternal(squaredTolerance) {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {number} Stride.
|
||||
*/
|
||||
getStride() {
|
||||
return this.stride;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {module:ol/geom/GeometryLayout} layout Layout.
|
||||
* @param {Array.<number>} flatCoordinates Flat coordinates.
|
||||
*/
|
||||
setFlatCoordinates(layout, flatCoordinates) {
|
||||
this.stride = getStrideForLayout(layout);
|
||||
this.layout = layout;
|
||||
this.flatCoordinates = flatCoordinates;
|
||||
}
|
||||
|
||||
/**
|
||||
* @abstract
|
||||
* @param {!Array} coordinates Coordinates.
|
||||
* @param {module:ol/geom/GeometryLayout=} opt_layout Layout.
|
||||
*/
|
||||
setCoordinates(coordinates, opt_layout) {}
|
||||
|
||||
/**
|
||||
* @param {module:ol/geom/GeometryLayout|undefined} layout Layout.
|
||||
* @param {Array} coordinates Coordinates.
|
||||
* @param {number} nesting Nesting.
|
||||
* @protected
|
||||
*/
|
||||
setLayout(layout, coordinates, nesting) {
|
||||
/** @type {number} */
|
||||
let stride;
|
||||
if (layout) {
|
||||
stride = getStrideForLayout(layout);
|
||||
} else {
|
||||
for (let i = 0; i < nesting; ++i) {
|
||||
if (coordinates.length === 0) {
|
||||
this.layout = GeometryLayout.XY;
|
||||
this.stride = 2;
|
||||
return;
|
||||
} else {
|
||||
coordinates = /** @type {Array} */ (coordinates[0]);
|
||||
}
|
||||
}
|
||||
stride = coordinates.length;
|
||||
layout = getLayoutForStride(stride);
|
||||
}
|
||||
this.layout = layout;
|
||||
this.stride = stride;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @api
|
||||
*/
|
||||
applyTransform(transformFn) {
|
||||
if (this.flatCoordinates) {
|
||||
transformFn(this.flatCoordinates, this.flatCoordinates, this.stride);
|
||||
this.changed();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @api
|
||||
*/
|
||||
rotate(angle, anchor) {
|
||||
const flatCoordinates = this.getFlatCoordinates();
|
||||
if (flatCoordinates) {
|
||||
const stride = this.getStride();
|
||||
rotate(
|
||||
flatCoordinates, 0, flatCoordinates.length,
|
||||
stride, angle, anchor, flatCoordinates);
|
||||
this.changed();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @api
|
||||
*/
|
||||
scale(sx, opt_sy, opt_anchor) {
|
||||
let sy = opt_sy;
|
||||
if (sy === undefined) {
|
||||
sy = sx;
|
||||
}
|
||||
let anchor = opt_anchor;
|
||||
if (!anchor) {
|
||||
anchor = getCenter(this.getExtent());
|
||||
}
|
||||
const flatCoordinates = this.getFlatCoordinates();
|
||||
if (flatCoordinates) {
|
||||
const stride = this.getStride();
|
||||
scale(
|
||||
flatCoordinates, 0, flatCoordinates.length,
|
||||
stride, sx, sy, anchor, flatCoordinates);
|
||||
this.changed();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @api
|
||||
*/
|
||||
translate(deltaX, deltaY) {
|
||||
const flatCoordinates = this.getFlatCoordinates();
|
||||
if (flatCoordinates) {
|
||||
const stride = this.getStride();
|
||||
translate(
|
||||
flatCoordinates, 0, flatCoordinates.length, stride,
|
||||
deltaX, deltaY, flatCoordinates);
|
||||
this.changed();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
@@ -88,234 +297,6 @@ export function getStrideForLayout(layout) {
|
||||
SimpleGeometry.prototype.containsXY = FALSE;
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
SimpleGeometry.prototype.computeExtent = function(extent) {
|
||||
return createOrUpdateFromFlatCoordinates(this.flatCoordinates,
|
||||
0, this.flatCoordinates.length, this.stride, extent);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @abstract
|
||||
* @return {Array} Coordinates.
|
||||
*/
|
||||
SimpleGeometry.prototype.getCoordinates = function() {};
|
||||
|
||||
|
||||
/**
|
||||
* Return the first coordinate of the geometry.
|
||||
* @return {module:ol/coordinate~Coordinate} First coordinate.
|
||||
* @api
|
||||
*/
|
||||
SimpleGeometry.prototype.getFirstCoordinate = function() {
|
||||
return this.flatCoordinates.slice(0, this.stride);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {Array.<number>} Flat coordinates.
|
||||
*/
|
||||
SimpleGeometry.prototype.getFlatCoordinates = function() {
|
||||
return this.flatCoordinates;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Return the last coordinate of the geometry.
|
||||
* @return {module:ol/coordinate~Coordinate} Last point.
|
||||
* @api
|
||||
*/
|
||||
SimpleGeometry.prototype.getLastCoordinate = function() {
|
||||
return this.flatCoordinates.slice(this.flatCoordinates.length - this.stride);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Return the {@link module:ol/geom/GeometryLayout~GeometryLayout layout} of the geometry.
|
||||
* @return {module:ol/geom/GeometryLayout} Layout.
|
||||
* @api
|
||||
*/
|
||||
SimpleGeometry.prototype.getLayout = function() {
|
||||
return this.layout;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
SimpleGeometry.prototype.getSimplifiedGeometry = function(squaredTolerance) {
|
||||
if (this.simplifiedGeometryRevision != this.getRevision()) {
|
||||
clear(this.simplifiedGeometryCache);
|
||||
this.simplifiedGeometryMaxMinSquaredTolerance = 0;
|
||||
this.simplifiedGeometryRevision = this.getRevision();
|
||||
}
|
||||
// If squaredTolerance is negative or if we know that simplification will not
|
||||
// have any effect then just return this.
|
||||
if (squaredTolerance < 0 ||
|
||||
(this.simplifiedGeometryMaxMinSquaredTolerance !== 0 &&
|
||||
squaredTolerance <= this.simplifiedGeometryMaxMinSquaredTolerance)) {
|
||||
return this;
|
||||
}
|
||||
const key = squaredTolerance.toString();
|
||||
if (this.simplifiedGeometryCache.hasOwnProperty(key)) {
|
||||
return this.simplifiedGeometryCache[key];
|
||||
} else {
|
||||
const simplifiedGeometry =
|
||||
this.getSimplifiedGeometryInternal(squaredTolerance);
|
||||
const simplifiedFlatCoordinates = simplifiedGeometry.getFlatCoordinates();
|
||||
if (simplifiedFlatCoordinates.length < this.flatCoordinates.length) {
|
||||
this.simplifiedGeometryCache[key] = simplifiedGeometry;
|
||||
return simplifiedGeometry;
|
||||
} else {
|
||||
// Simplification did not actually remove any coordinates. We now know
|
||||
// that any calls to getSimplifiedGeometry with a squaredTolerance less
|
||||
// than or equal to the current squaredTolerance will also not have any
|
||||
// effect. This allows us to short circuit simplification (saving CPU
|
||||
// cycles) and prevents the cache of simplified geometries from filling
|
||||
// up with useless identical copies of this geometry (saving memory).
|
||||
this.simplifiedGeometryMaxMinSquaredTolerance = squaredTolerance;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {number} squaredTolerance Squared tolerance.
|
||||
* @return {module:ol/geom/SimpleGeometry} Simplified geometry.
|
||||
* @protected
|
||||
*/
|
||||
SimpleGeometry.prototype.getSimplifiedGeometryInternal = function(squaredTolerance) {
|
||||
return this;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {number} Stride.
|
||||
*/
|
||||
SimpleGeometry.prototype.getStride = function() {
|
||||
return this.stride;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {module:ol/geom/GeometryLayout} layout Layout.
|
||||
* @param {Array.<number>} flatCoordinates Flat coordinates.
|
||||
*/
|
||||
SimpleGeometry.prototype.setFlatCoordinates = function(layout, flatCoordinates) {
|
||||
this.stride = getStrideForLayout(layout);
|
||||
this.layout = layout;
|
||||
this.flatCoordinates = flatCoordinates;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @abstract
|
||||
* @param {!Array} coordinates Coordinates.
|
||||
* @param {module:ol/geom/GeometryLayout=} opt_layout Layout.
|
||||
*/
|
||||
SimpleGeometry.prototype.setCoordinates = function(coordinates, opt_layout) {};
|
||||
|
||||
|
||||
/**
|
||||
* @param {module:ol/geom/GeometryLayout|undefined} layout Layout.
|
||||
* @param {Array} coordinates Coordinates.
|
||||
* @param {number} nesting Nesting.
|
||||
* @protected
|
||||
*/
|
||||
SimpleGeometry.prototype.setLayout = function(layout, coordinates, nesting) {
|
||||
/** @type {number} */
|
||||
let stride;
|
||||
if (layout) {
|
||||
stride = getStrideForLayout(layout);
|
||||
} else {
|
||||
for (let i = 0; i < nesting; ++i) {
|
||||
if (coordinates.length === 0) {
|
||||
this.layout = GeometryLayout.XY;
|
||||
this.stride = 2;
|
||||
return;
|
||||
} else {
|
||||
coordinates = /** @type {Array} */ (coordinates[0]);
|
||||
}
|
||||
}
|
||||
stride = coordinates.length;
|
||||
layout = getLayoutForStride(stride);
|
||||
}
|
||||
this.layout = layout;
|
||||
this.stride = stride;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @api
|
||||
*/
|
||||
SimpleGeometry.prototype.applyTransform = function(transformFn) {
|
||||
if (this.flatCoordinates) {
|
||||
transformFn(this.flatCoordinates, this.flatCoordinates, this.stride);
|
||||
this.changed();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @api
|
||||
*/
|
||||
SimpleGeometry.prototype.rotate = function(angle, anchor) {
|
||||
const flatCoordinates = this.getFlatCoordinates();
|
||||
if (flatCoordinates) {
|
||||
const stride = this.getStride();
|
||||
rotate(
|
||||
flatCoordinates, 0, flatCoordinates.length,
|
||||
stride, angle, anchor, flatCoordinates);
|
||||
this.changed();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @api
|
||||
*/
|
||||
SimpleGeometry.prototype.scale = function(sx, opt_sy, opt_anchor) {
|
||||
let sy = opt_sy;
|
||||
if (sy === undefined) {
|
||||
sy = sx;
|
||||
}
|
||||
let anchor = opt_anchor;
|
||||
if (!anchor) {
|
||||
anchor = getCenter(this.getExtent());
|
||||
}
|
||||
const flatCoordinates = this.getFlatCoordinates();
|
||||
if (flatCoordinates) {
|
||||
const stride = this.getStride();
|
||||
scale(
|
||||
flatCoordinates, 0, flatCoordinates.length,
|
||||
stride, sx, sy, anchor, flatCoordinates);
|
||||
this.changed();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @api
|
||||
*/
|
||||
SimpleGeometry.prototype.translate = function(deltaX, deltaY) {
|
||||
const flatCoordinates = this.getFlatCoordinates();
|
||||
if (flatCoordinates) {
|
||||
const stride = this.getStride();
|
||||
translate(
|
||||
flatCoordinates, 0, flatCoordinates.length, stride,
|
||||
deltaX, deltaY, flatCoordinates);
|
||||
this.changed();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {module:ol/geom/SimpleGeometry} simpleGeometry Simple geometry.
|
||||
* @param {module:ol/transform~Transform} transform Transform.
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user