Publishing edit branch
This commit is contained in:
@@ -0,0 +1,4 @@
|
||||
@exportFunction ol.animation.bounce ol.animation.BounceOptions ol.PreRenderFunction
|
||||
@exportFunction ol.animation.pan ol.animation.PanOptions ol.PreRenderFunction
|
||||
@exportFunction ol.animation.rotate ol.animation.RotateOptions ol.PreRenderFunction
|
||||
@exportFunction ol.animation.zoom ol.animation.ZoomOptions ol.PreRenderFunction
|
||||
@@ -0,0 +1,150 @@
|
||||
// FIXME works for View2D only
|
||||
|
||||
goog.provide('ol.animation');
|
||||
|
||||
goog.require('ol.PreRenderFunction');
|
||||
goog.require('ol.ViewHint');
|
||||
goog.require('ol.easing');
|
||||
|
||||
|
||||
/**
|
||||
* @param {ol.animation.BounceOptions} options Bounce options.
|
||||
* @return {ol.PreRenderFunction} Pre-render function.
|
||||
*/
|
||||
ol.animation.bounce = function(options) {
|
||||
var resolution = options.resolution;
|
||||
var start = goog.isDef(options.start) ? options.start : goog.now();
|
||||
var duration = goog.isDef(options.duration) ? options.duration : 1000;
|
||||
var easing = goog.isDef(options.easing) ?
|
||||
options.easing : ol.easing.upAndDown;
|
||||
return (
|
||||
/**
|
||||
* @param {ol.Map} map Map.
|
||||
* @param {?ol.FrameState} frameState Frame state.
|
||||
*/
|
||||
function(map, frameState) {
|
||||
if (frameState.time < start) {
|
||||
frameState.animate = true;
|
||||
frameState.viewHints[ol.ViewHint.ANIMATING] += 1;
|
||||
return true;
|
||||
} else if (frameState.time < start + duration) {
|
||||
var delta = easing((frameState.time - start) / duration);
|
||||
var deltaResolution = resolution - frameState.view2DState.resolution;
|
||||
frameState.animate = true;
|
||||
frameState.view2DState.resolution += delta * deltaResolution;
|
||||
frameState.viewHints[ol.ViewHint.ANIMATING] += 1;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {ol.animation.PanOptions} options Pan options.
|
||||
* @return {ol.PreRenderFunction} Pre-render function.
|
||||
*/
|
||||
ol.animation.pan = function(options) {
|
||||
var source = options.source;
|
||||
var start = goog.isDef(options.start) ? options.start : goog.now();
|
||||
var sourceX = source[0];
|
||||
var sourceY = source[1];
|
||||
var duration = goog.isDef(options.duration) ? options.duration : 1000;
|
||||
var easing = goog.isDef(options.easing) ?
|
||||
options.easing : ol.easing.inAndOut;
|
||||
return (
|
||||
/**
|
||||
* @param {ol.Map} map Map.
|
||||
* @param {?ol.FrameState} frameState Frame state.
|
||||
*/
|
||||
function(map, frameState) {
|
||||
if (frameState.time < start) {
|
||||
frameState.animate = true;
|
||||
frameState.viewHints[ol.ViewHint.ANIMATING] += 1;
|
||||
return true;
|
||||
} else if (frameState.time < start + duration) {
|
||||
var delta = 1 - easing((frameState.time - start) / duration);
|
||||
var deltaX = sourceX - frameState.view2DState.center[0];
|
||||
var deltaY = sourceY - frameState.view2DState.center[1];
|
||||
frameState.animate = true;
|
||||
frameState.view2DState.center[0] += delta * deltaX;
|
||||
frameState.view2DState.center[1] += delta * deltaY;
|
||||
frameState.viewHints[ol.ViewHint.ANIMATING] += 1;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {ol.animation.RotateOptions} options Rotate options.
|
||||
* @return {ol.PreRenderFunction} Pre-render function.
|
||||
*/
|
||||
ol.animation.rotate = function(options) {
|
||||
var sourceRotation = options.rotation;
|
||||
var start = goog.isDef(options.start) ? options.start : goog.now();
|
||||
var duration = goog.isDef(options.duration) ? options.duration : 1000;
|
||||
var easing = goog.isDef(options.easing) ?
|
||||
options.easing : ol.easing.inAndOut;
|
||||
|
||||
return (
|
||||
/**
|
||||
* @param {ol.Map} map Map.
|
||||
* @param {?ol.FrameState} frameState Frame state.
|
||||
*/
|
||||
function(map, frameState) {
|
||||
if (frameState.time < start) {
|
||||
frameState.animate = true;
|
||||
frameState.viewHints[ol.ViewHint.ANIMATING] += 1;
|
||||
return true;
|
||||
} else if (frameState.time < start + duration) {
|
||||
var delta = 1 - easing((frameState.time - start) / duration);
|
||||
var deltaRotation =
|
||||
sourceRotation - frameState.view2DState.rotation;
|
||||
frameState.animate = true;
|
||||
frameState.view2DState.rotation += delta * deltaRotation;
|
||||
frameState.viewHints[ol.ViewHint.ANIMATING] += 1;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {ol.animation.ZoomOptions} options Zoom options.
|
||||
* @return {ol.PreRenderFunction} Pre-render function.
|
||||
*/
|
||||
ol.animation.zoom = function(options) {
|
||||
var sourceResolution = options.resolution;
|
||||
var start = goog.isDef(options.start) ? options.start : goog.now();
|
||||
var duration = goog.isDef(options.duration) ? options.duration : 1000;
|
||||
var easing = goog.isDef(options.easing) ?
|
||||
options.easing : ol.easing.inAndOut;
|
||||
return (
|
||||
/**
|
||||
* @param {ol.Map} map Map.
|
||||
* @param {?ol.FrameState} frameState Frame state.
|
||||
*/
|
||||
function(map, frameState) {
|
||||
if (frameState.time < start) {
|
||||
frameState.animate = true;
|
||||
frameState.viewHints[ol.ViewHint.ANIMATING] += 1;
|
||||
return true;
|
||||
} else if (frameState.time < start + duration) {
|
||||
var delta = 1 - easing((frameState.time - start) / duration);
|
||||
var deltaResolution =
|
||||
sourceResolution - frameState.view2DState.resolution;
|
||||
frameState.animate = true;
|
||||
frameState.view2DState.resolution += delta * deltaResolution;
|
||||
frameState.viewHints[ol.ViewHint.ANIMATING] += 1;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,12 @@
|
||||
/**
|
||||
* The {ol.animation} static methods are designed to be used with the {@link ol.Map#beforeRender} method. For example:
|
||||
*
|
||||
* var map = new ol.Map({ ... });
|
||||
* var zoom = ol.animation.zoom({
|
||||
* resolution: map.getView().getResolution()
|
||||
* });
|
||||
* map.beforeRender(zoom);
|
||||
* map.getView().setResolution(map.getView().getResolution() * 2);
|
||||
*
|
||||
* @namespace ol.animation
|
||||
*/
|
||||
@@ -0,0 +1,86 @@
|
||||
goog.provide('ol.array');
|
||||
|
||||
goog.require('goog.array');
|
||||
goog.require('goog.asserts');
|
||||
|
||||
|
||||
/**
|
||||
* @param {Array.<number>} arr Array.
|
||||
* @param {number} target Target.
|
||||
* @return {number} Index.
|
||||
*/
|
||||
ol.array.binaryFindNearest = function(arr, target) {
|
||||
var index = goog.array.binarySearch(arr, target,
|
||||
/**
|
||||
* @param {number} a A.
|
||||
* @param {number} b B.
|
||||
* @return {number} b minus a.
|
||||
*/
|
||||
function(a, b) {
|
||||
return b - a;
|
||||
});
|
||||
if (index >= 0) {
|
||||
return index;
|
||||
} else if (index == -1) {
|
||||
return 0;
|
||||
} else if (index == -arr.length - 1) {
|
||||
return arr.length - 1;
|
||||
} else {
|
||||
var left = -index - 2;
|
||||
var right = -index - 1;
|
||||
if (arr[left] - target < target - arr[right]) {
|
||||
return left;
|
||||
} else {
|
||||
return right;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {Array.<number>} arr Array.
|
||||
* @param {number} target Target.
|
||||
* @param {number} direction 0 means return the nearest, > 0
|
||||
* means return the largest nearest, < 0 means return the
|
||||
* smallest nearest.
|
||||
* @return {number} Index.
|
||||
*/
|
||||
ol.array.linearFindNearest = function(arr, target, direction) {
|
||||
var n = arr.length;
|
||||
if (arr[0] <= target) {
|
||||
return 0;
|
||||
} else if (target <= arr[n - 1]) {
|
||||
return n - 1;
|
||||
} else {
|
||||
var i;
|
||||
if (direction > 0) {
|
||||
for (i = 1; i < n; ++i) {
|
||||
if (arr[i] < target) {
|
||||
return i - 1;
|
||||
}
|
||||
}
|
||||
} else if (direction < 0) {
|
||||
for (i = 1; i < n; ++i) {
|
||||
if (arr[i] <= target) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (i = 1; i < n; ++i) {
|
||||
if (arr[i] == target) {
|
||||
return i;
|
||||
} else if (arr[i] < target) {
|
||||
if (arr[i - 1] - target < target - arr[i]) {
|
||||
return i - 1;
|
||||
} else {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// We should never get here, but the compiler complains
|
||||
// if it finds a path for which no number is returned.
|
||||
goog.asserts.fail();
|
||||
return n - 1;
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1 @@
|
||||
@exportClass ol.Attribution ol.AttributionOptions
|
||||
@@ -0,0 +1,72 @@
|
||||
goog.provide('ol.Attribution');
|
||||
|
||||
goog.require('ol.TileRange');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Create a new attribution to be associated with a layer source.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* source: new ol.source.OSM({
|
||||
* attributions: [
|
||||
* new ol.Attribution({
|
||||
* html: 'All maps © ' +
|
||||
* '<a href="http://www.opencyclemap.org/">OpenCycleMap</a>'
|
||||
* }),
|
||||
* ol.source.OSM.DATA_ATTRIBUTION
|
||||
* ],
|
||||
* ..
|
||||
*
|
||||
* @constructor
|
||||
* @param {ol.AttributionOptions} options Attribution options.
|
||||
*/
|
||||
ol.Attribution = function(options) {
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {string}
|
||||
*/
|
||||
this.html_ = options.html;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {Object.<string, Array.<ol.TileRange>>}
|
||||
*/
|
||||
this.tileRanges_ = goog.isDef(options.tileRanges) ?
|
||||
options.tileRanges : null;
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {string} HTML.
|
||||
*/
|
||||
ol.Attribution.prototype.getHTML = function() {
|
||||
return this.html_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {Object.<string, ol.TileRange>} tileRanges Tile ranges.
|
||||
* @return {boolean} Intersects any tile range.
|
||||
*/
|
||||
ol.Attribution.prototype.intersectsAnyTileRange = function(tileRanges) {
|
||||
if (goog.isNull(this.tileRanges_)) {
|
||||
return true;
|
||||
}
|
||||
var i, ii, tileRange, z;
|
||||
for (z in tileRanges) {
|
||||
if (!(z in this.tileRanges_)) {
|
||||
continue;
|
||||
}
|
||||
tileRange = tileRanges[z];
|
||||
for (i = 0, ii = this.tileRanges_[z].length; i < ii; ++i) {
|
||||
if (this.tileRanges_[z][i].intersects(tileRange)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
@@ -0,0 +1,22 @@
|
||||
goog.provide('ol.BrowserFeature');
|
||||
|
||||
|
||||
/**
|
||||
* @define {boolean} Assume touch.
|
||||
*/
|
||||
ol.ASSUME_TOUCH = false;
|
||||
|
||||
|
||||
/**
|
||||
* @type {Object}
|
||||
*/
|
||||
ol.BrowserFeature = {
|
||||
/**
|
||||
* True if browser supports touch events.
|
||||
* @type {boolean}
|
||||
*/
|
||||
HAS_TOUCH: ol.ASSUME_TOUCH ||
|
||||
(goog.global.document &&
|
||||
'ontouchstart' in goog.global.document.documentElement) ||
|
||||
!!(goog.global.navigator.msPointerEnabled)
|
||||
};
|
||||
@@ -0,0 +1 @@
|
||||
@exportSymbol ol.canvas.SUPPORTED
|
||||
@@ -0,0 +1,24 @@
|
||||
goog.provide('ol.canvas');
|
||||
goog.provide('ol.canvas.SUPPORTED');
|
||||
|
||||
goog.require('goog.dom');
|
||||
goog.require('goog.dom.TagName');
|
||||
|
||||
|
||||
/**
|
||||
* Is supported.
|
||||
* @const
|
||||
* @type {boolean}
|
||||
*/
|
||||
ol.canvas.SUPPORTED = (function() {
|
||||
if (!('HTMLCanvasElement' in goog.global)) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
var canvas = /** @type {HTMLCanvasElement} */
|
||||
(goog.dom.createElement(goog.dom.TagName.CANVAS));
|
||||
return !goog.isNull(canvas.getContext('2d'));
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
})();
|
||||
@@ -0,0 +1,15 @@
|
||||
@exportSymbol ol.Collection
|
||||
@exportProperty ol.Collection.prototype.clear
|
||||
@exportProperty ol.Collection.prototype.extend
|
||||
@exportProperty ol.Collection.prototype.forEach
|
||||
@exportProperty ol.Collection.prototype.getArray
|
||||
@exportProperty ol.Collection.prototype.getAt
|
||||
@exportProperty ol.Collection.prototype.getLength
|
||||
@exportProperty ol.Collection.prototype.insertAt
|
||||
@exportProperty ol.Collection.prototype.pop
|
||||
@exportProperty ol.Collection.prototype.push
|
||||
@exportProperty ol.Collection.prototype.remove
|
||||
@exportProperty ol.Collection.prototype.removeAt
|
||||
@exportProperty ol.Collection.prototype.setAt
|
||||
|
||||
@exportProperty ol.CollectionEvent.prototype.getElement
|
||||
@@ -0,0 +1,248 @@
|
||||
|
||||
/**
|
||||
* An implementation of Google Maps' MVCArray.
|
||||
* @see https://developers.google.com/maps/documentation/javascript/reference
|
||||
*/
|
||||
|
||||
goog.provide('ol.Collection');
|
||||
goog.provide('ol.CollectionEvent');
|
||||
goog.provide('ol.CollectionEventType');
|
||||
|
||||
goog.require('goog.array');
|
||||
goog.require('goog.events.Event');
|
||||
goog.require('ol.Object');
|
||||
|
||||
|
||||
/**
|
||||
* @enum {string}
|
||||
*/
|
||||
ol.CollectionEventType = {
|
||||
ADD: 'add',
|
||||
REMOVE: 'remove'
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
* @extends {goog.events.Event}
|
||||
* @param {ol.CollectionEventType} type Type.
|
||||
* @param {*=} opt_elem Element.
|
||||
* @param {Object=} opt_target Target.
|
||||
*/
|
||||
ol.CollectionEvent = function(type, opt_elem, opt_target) {
|
||||
|
||||
goog.base(this, type, opt_target);
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {*}
|
||||
*/
|
||||
this.elem_ = opt_elem;
|
||||
|
||||
};
|
||||
goog.inherits(ol.CollectionEvent, goog.events.Event);
|
||||
|
||||
|
||||
/**
|
||||
* @return {*} The element to which this event pertains.
|
||||
*/
|
||||
ol.CollectionEvent.prototype.getElement = function() {
|
||||
return this.elem_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @enum {string}
|
||||
*/
|
||||
ol.CollectionProperty = {
|
||||
LENGTH: 'length'
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* A mutable MVC Array.
|
||||
* @constructor
|
||||
* @extends {ol.Object}
|
||||
* @param {Array=} opt_array Array.
|
||||
*/
|
||||
ol.Collection = function(opt_array) {
|
||||
|
||||
goog.base(this);
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {Array}
|
||||
*/
|
||||
this.array_ = opt_array || [];
|
||||
|
||||
this.updateLength_();
|
||||
|
||||
};
|
||||
goog.inherits(ol.Collection, ol.Object);
|
||||
|
||||
|
||||
/**
|
||||
* Remove all elements from the collection.
|
||||
*/
|
||||
ol.Collection.prototype.clear = function() {
|
||||
while (this.getLength() > 0) {
|
||||
this.pop();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {Array} arr Array.
|
||||
* @return {ol.Collection} This collection.
|
||||
*/
|
||||
ol.Collection.prototype.extend = function(arr) {
|
||||
var i, ii;
|
||||
for (i = 0, ii = arr.length; i < ii; ++i) {
|
||||
this.push(arr[i]);
|
||||
}
|
||||
return this;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Iterate over each element, calling the provided callback.
|
||||
* @param {Function} 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.
|
||||
* @param {Object=} opt_obj The object to be used as the value of 'this'
|
||||
* within f.
|
||||
*/
|
||||
ol.Collection.prototype.forEach = function(f, opt_obj) {
|
||||
goog.array.forEach(this.array_, f, opt_obj);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* 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} Array.
|
||||
*/
|
||||
ol.Collection.prototype.getArray = function() {
|
||||
return this.array_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get the element at the provided index.
|
||||
* @param {number} index Index.
|
||||
* @return {*} Element.
|
||||
*/
|
||||
ol.Collection.prototype.getAt = function(index) {
|
||||
return this.array_[index];
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get the length of this collection.
|
||||
* @return {number} Length.
|
||||
*/
|
||||
ol.Collection.prototype.getLength = function() {
|
||||
return /** @type {number} */ (this.get(ol.CollectionProperty.LENGTH));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Insert an element at the provided index.
|
||||
* @param {number} index Index.
|
||||
* @param {*} elem Element.
|
||||
*/
|
||||
ol.Collection.prototype.insertAt = function(index, elem) {
|
||||
goog.array.insertAt(this.array_, elem, index);
|
||||
this.updateLength_();
|
||||
this.dispatchEvent(
|
||||
new ol.CollectionEvent(ol.CollectionEventType.ADD, elem, this));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Remove the last element of the collection.
|
||||
* @return {*} Element.
|
||||
*/
|
||||
ol.Collection.prototype.pop = function() {
|
||||
return this.removeAt(this.getLength() - 1);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Insert the provided element at the end of the collection.
|
||||
* @param {*} elem Element.
|
||||
* @return {number} Length.
|
||||
*/
|
||||
ol.Collection.prototype.push = function(elem) {
|
||||
var n = this.array_.length;
|
||||
this.insertAt(n, elem);
|
||||
return n;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Removes the first occurence of elem from the collection.
|
||||
* @param {*} elem Element.
|
||||
* @return {*} The removed element or undefined if elem was not found.
|
||||
*/
|
||||
ol.Collection.prototype.remove = function(elem) {
|
||||
var arr = this.array_;
|
||||
var i, ii;
|
||||
for (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.
|
||||
* @param {number} index Index.
|
||||
* @return {*} Value.
|
||||
*/
|
||||
ol.Collection.prototype.removeAt = function(index) {
|
||||
var prev = this.array_[index];
|
||||
goog.array.removeAt(this.array_, index);
|
||||
this.updateLength_();
|
||||
this.dispatchEvent(
|
||||
new ol.CollectionEvent(ol.CollectionEventType.REMOVE, prev, this));
|
||||
return prev;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Set the element at the provided index.
|
||||
* @param {number} index Index.
|
||||
* @param {*} elem Element.
|
||||
*/
|
||||
ol.Collection.prototype.setAt = function(index, elem) {
|
||||
var n = this.getLength();
|
||||
if (index < n) {
|
||||
var prev = this.array_[index];
|
||||
this.array_[index] = elem;
|
||||
this.dispatchEvent(
|
||||
new ol.CollectionEvent(ol.CollectionEventType.REMOVE, prev, this));
|
||||
this.dispatchEvent(
|
||||
new ol.CollectionEvent(ol.CollectionEventType.ADD, elem, this));
|
||||
} else {
|
||||
var j;
|
||||
for (j = n; j < index; ++j) {
|
||||
this.insertAt(j, undefined);
|
||||
}
|
||||
this.insertAt(index, elem);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
ol.Collection.prototype.updateLength_ = function() {
|
||||
this.set(ol.CollectionProperty.LENGTH, this.array_.length);
|
||||
};
|
||||
@@ -0,0 +1,62 @@
|
||||
goog.provide('ol.Color');
|
||||
|
||||
goog.require('goog.color');
|
||||
goog.require('goog.math');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
* @param {number} r Red, 0 to 255.
|
||||
* @param {number} g Green, 0 to 255.
|
||||
* @param {number} b Blue, 0 to 255.
|
||||
* @param {number} a Alpha, 0 (fully transparent) to 1 (fully opaque).
|
||||
*/
|
||||
ol.Color = function(r, g, b, a) {
|
||||
|
||||
/**
|
||||
* @type {number}
|
||||
*/
|
||||
this.r = goog.math.clamp(r, 0, 255);
|
||||
|
||||
/**
|
||||
* @type {number}
|
||||
*/
|
||||
this.g = goog.math.clamp(g, 0, 255);
|
||||
|
||||
/**
|
||||
* @type {number}
|
||||
*/
|
||||
this.b = goog.math.clamp(b, 0, 255);
|
||||
|
||||
/**
|
||||
* @type {number}
|
||||
*/
|
||||
this.a = goog.math.clamp(a, 0, 1);
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {string} str String.
|
||||
* @param {number=} opt_a Alpha.
|
||||
* @return {ol.Color} Color.
|
||||
*/
|
||||
ol.Color.createFromString = function(str, opt_a) {
|
||||
var rgb = goog.color.hexToRgb(goog.color.parse(str).hex);
|
||||
var a = goog.isDef(opt_a) ? opt_a : 1;
|
||||
return new ol.Color(rgb[0], rgb[1], rgb[2], a);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {ol.Color} color1 Color 1.
|
||||
* @param {ol.Color} color2 Color 2.
|
||||
* @return {boolean} Equals.
|
||||
*/
|
||||
ol.Color.equals = function(color1, color2) {
|
||||
return (color1.r == color2.r &&
|
||||
color1.g == color2.g &&
|
||||
color1.b == color2.b &&
|
||||
color1.a == color2.a);
|
||||
};
|
||||
@@ -0,0 +1,27 @@
|
||||
goog.provide('ol.Constraints');
|
||||
|
||||
goog.require('ol.ResolutionConstraintType');
|
||||
goog.require('ol.RotationConstraintType');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
* @param {ol.ResolutionConstraintType} resolutionConstraint
|
||||
* Resolution constraint.
|
||||
* @param {ol.RotationConstraintType} rotationConstraint
|
||||
* Rotation constraint.
|
||||
*/
|
||||
ol.Constraints = function(resolutionConstraint, rotationConstraint) {
|
||||
|
||||
/**
|
||||
* @type {ol.ResolutionConstraintType}
|
||||
*/
|
||||
this.resolution = resolutionConstraint;
|
||||
|
||||
/**
|
||||
* @type {ol.RotationConstraintType}
|
||||
*/
|
||||
this.rotation = rotationConstraint;
|
||||
|
||||
};
|
||||
@@ -0,0 +1,3 @@
|
||||
/**
|
||||
* @namespace ol.control
|
||||
*/
|
||||
@@ -0,0 +1,2 @@
|
||||
@exportClass ol.control.Attribution ol.control.AttributionOptions
|
||||
@exportProperty ol.control.Attribution.prototype.setMap
|
||||
@@ -0,0 +1,188 @@
|
||||
// FIXME handle date line wrap
|
||||
|
||||
goog.provide('ol.control.Attribution');
|
||||
|
||||
goog.require('goog.array');
|
||||
goog.require('goog.dom');
|
||||
goog.require('goog.dom.TagName');
|
||||
goog.require('goog.object');
|
||||
goog.require('goog.style');
|
||||
goog.require('ol.Attribution');
|
||||
goog.require('ol.FrameState');
|
||||
goog.require('ol.control.Control');
|
||||
goog.require('ol.css');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Create a new attribution control to show all the attributions associated
|
||||
* with the layer sources in the map. A default map has this control included.
|
||||
* By default it will show in the bottom right portion of the map, but it can
|
||||
* be changed by using a css selector for .ol-attribution.
|
||||
* @constructor
|
||||
* @extends {ol.control.Control}
|
||||
* @param {ol.control.AttributionOptions=} opt_options Attribution options.
|
||||
*/
|
||||
ol.control.Attribution = function(opt_options) {
|
||||
|
||||
var options = goog.isDef(opt_options) ? opt_options : {};
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {Element}
|
||||
*/
|
||||
this.ulElement_ = goog.dom.createElement(goog.dom.TagName.UL);
|
||||
|
||||
var className = goog.isDef(options.className) ?
|
||||
options.className : 'ol-attribution';
|
||||
var element = goog.dom.createDom(goog.dom.TagName.DIV, {
|
||||
'class': className + ' ' + ol.css.CLASS_UNSELECTABLE
|
||||
}, this.ulElement_);
|
||||
|
||||
goog.base(this, {
|
||||
element: element,
|
||||
target: options.target
|
||||
});
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.renderedVisible_ = true;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {Object.<string, Element>}
|
||||
*/
|
||||
this.attributionElements_ = {};
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {Object.<string, boolean>}
|
||||
*/
|
||||
this.attributionElementRenderedVisible_ = {};
|
||||
|
||||
};
|
||||
goog.inherits(ol.control.Attribution, ol.control.Control);
|
||||
|
||||
|
||||
/**
|
||||
* @param {?ol.FrameState} frameState Frame state.
|
||||
* @return {Array.<Object.<string, ol.Attribution>>} Attributions.
|
||||
*/
|
||||
ol.control.Attribution.prototype.getSourceAttributions =
|
||||
function(frameState) {
|
||||
var i, ii, j, jj, tileRanges, source, sourceAttribution,
|
||||
sourceAttributionKey, sourceAttributions, sourceKey;
|
||||
var layers = frameState.layersArray;
|
||||
/** @type {Object.<string, ol.Attribution>} */
|
||||
var attributions = goog.object.clone(frameState.attributions);
|
||||
/** @type {Object.<string, ol.Attribution>} */
|
||||
var hiddenAttributions = {};
|
||||
for (i = 0, ii = layers.length; i < ii; i++) {
|
||||
source = layers[i].getSource();
|
||||
sourceKey = goog.getUid(source).toString();
|
||||
sourceAttributions = source.getAttributions();
|
||||
if (goog.isNull(sourceAttributions)) {
|
||||
continue;
|
||||
}
|
||||
for (j = 0, jj = sourceAttributions.length; j < jj; j++) {
|
||||
sourceAttribution = sourceAttributions[j];
|
||||
sourceAttributionKey = goog.getUid(sourceAttribution).toString();
|
||||
if (sourceAttributionKey in attributions) {
|
||||
continue;
|
||||
}
|
||||
tileRanges = frameState.usedTiles[sourceKey];
|
||||
if (goog.isDef(tileRanges) &&
|
||||
sourceAttribution.intersectsAnyTileRange(tileRanges)) {
|
||||
if (sourceAttributionKey in hiddenAttributions) {
|
||||
delete hiddenAttributions[sourceAttributionKey];
|
||||
}
|
||||
attributions[sourceAttributionKey] = sourceAttribution;
|
||||
}
|
||||
else {
|
||||
hiddenAttributions[sourceAttributionKey] = sourceAttribution;
|
||||
}
|
||||
}
|
||||
}
|
||||
return [attributions, hiddenAttributions];
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
ol.control.Attribution.prototype.handleMapPostrender = function(mapEvent) {
|
||||
this.updateElement_(mapEvent.frameState);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {?ol.FrameState} frameState Frame state.
|
||||
*/
|
||||
ol.control.Attribution.prototype.updateElement_ = function(frameState) {
|
||||
|
||||
if (goog.isNull(frameState)) {
|
||||
if (this.renderedVisible_) {
|
||||
goog.style.setElementShown(this.element, false);
|
||||
this.renderedVisible_ = false;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
var attributions = this.getSourceAttributions(frameState);
|
||||
/** @type {Object.<string, ol.Attribution>} */
|
||||
var visibleAttributions = attributions[0];
|
||||
/** @type {Object.<string, ol.Attribution>} */
|
||||
var hiddenAttributions = attributions[1];
|
||||
|
||||
var attributionElement, attributionKey;
|
||||
for (attributionKey in this.attributionElements_) {
|
||||
if (attributionKey in visibleAttributions) {
|
||||
if (!this.attributionElementRenderedVisible_[attributionKey]) {
|
||||
goog.style.setElementShown(
|
||||
this.attributionElements_[attributionKey], true);
|
||||
this.attributionElementRenderedVisible_[attributionKey] = true;
|
||||
}
|
||||
delete visibleAttributions[attributionKey];
|
||||
}
|
||||
else if (attributionKey in hiddenAttributions) {
|
||||
if (this.attributionElementRenderedVisible_[attributionKey]) {
|
||||
goog.style.setElementShown(
|
||||
this.attributionElements_[attributionKey], false);
|
||||
delete this.attributionElementRenderedVisible_[attributionKey];
|
||||
}
|
||||
delete hiddenAttributions[attributionKey];
|
||||
}
|
||||
else {
|
||||
goog.dom.removeNode(this.attributionElements_[attributionKey]);
|
||||
delete this.attributionElements_[attributionKey];
|
||||
delete this.attributionElementRenderedVisible_[attributionKey];
|
||||
}
|
||||
}
|
||||
for (attributionKey in visibleAttributions) {
|
||||
attributionElement = goog.dom.createElement(goog.dom.TagName.LI);
|
||||
attributionElement.innerHTML =
|
||||
visibleAttributions[attributionKey].getHTML();
|
||||
goog.dom.appendChild(this.ulElement_, attributionElement);
|
||||
this.attributionElements_[attributionKey] = attributionElement;
|
||||
this.attributionElementRenderedVisible_[attributionKey] = true;
|
||||
}
|
||||
for (attributionKey in hiddenAttributions) {
|
||||
attributionElement = goog.dom.createElement(goog.dom.TagName.LI);
|
||||
attributionElement.innerHTML =
|
||||
hiddenAttributions[attributionKey].getHTML();
|
||||
goog.style.setElementShown(attributionElement, false);
|
||||
goog.dom.appendChild(this.ulElement_, attributionElement);
|
||||
this.attributionElements_[attributionKey] = attributionElement;
|
||||
}
|
||||
|
||||
var renderVisible =
|
||||
!goog.object.isEmpty(this.attributionElementRenderedVisible_);
|
||||
if (this.renderedVisible_ != renderVisible) {
|
||||
goog.style.setElementShown(this.element, renderVisible);
|
||||
this.renderedVisible_ = renderVisible;
|
||||
}
|
||||
|
||||
};
|
||||
@@ -0,0 +1,3 @@
|
||||
@exportClass ol.control.Control ol.control.ControlOptions
|
||||
@exportProperty ol.control.Control.prototype.getMap
|
||||
@exportProperty ol.control.Control.prototype.setMap
|
||||
@@ -0,0 +1,103 @@
|
||||
goog.provide('ol.control.Control');
|
||||
|
||||
goog.require('goog.array');
|
||||
goog.require('goog.dom');
|
||||
goog.require('goog.events');
|
||||
goog.require('ol.MapEventType');
|
||||
goog.require('ol.Object');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Something to be painted over the map to provide a means for interaction
|
||||
* (buttons) or to show annotations (status bars).
|
||||
*
|
||||
* @constructor
|
||||
* @extends {ol.Object}
|
||||
* @implements {oli.control.Control}
|
||||
* @param {ol.control.ControlOptions} options Control options.
|
||||
*/
|
||||
ol.control.Control = function(options) {
|
||||
|
||||
goog.base(this);
|
||||
|
||||
/**
|
||||
* @protected
|
||||
* @type {Element}
|
||||
*/
|
||||
this.element = goog.isDef(options.element) ? options.element : null;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {Element|undefined}
|
||||
*/
|
||||
this.target_ = options.target;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {ol.Map}
|
||||
*/
|
||||
this.map_ = null;
|
||||
|
||||
/**
|
||||
* @protected
|
||||
* @type {!Array.<?number>}
|
||||
*/
|
||||
this.listenerKeys = [];
|
||||
|
||||
};
|
||||
goog.inherits(ol.control.Control, ol.Object);
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
ol.control.Control.prototype.disposeInternal = function() {
|
||||
goog.dom.removeNode(this.element);
|
||||
goog.base(this, 'disposeInternal');
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get the map associated with this control.
|
||||
* @return {ol.Map} Map.
|
||||
*/
|
||||
ol.control.Control.prototype.getMap = function() {
|
||||
return this.map_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Function called on each map render. Executes in a requestAnimationFrame
|
||||
* callback. Can be implemented in sub-classes to re-render the control's
|
||||
* UI.
|
||||
* @param {ol.MapEvent} mapEvent Map event.
|
||||
*/
|
||||
ol.control.Control.prototype.handleMapPostrender = goog.nullFunction;
|
||||
|
||||
|
||||
/**
|
||||
* 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 {ol.Map} map Map.
|
||||
*/
|
||||
ol.control.Control.prototype.setMap = function(map) {
|
||||
if (!goog.isNull(this.map_)) {
|
||||
goog.dom.removeNode(this.element);
|
||||
}
|
||||
if (!goog.array.isEmpty(this.listenerKeys)) {
|
||||
goog.array.forEach(this.listenerKeys, goog.events.unlistenByKey);
|
||||
this.listenerKeys.length = 0;
|
||||
}
|
||||
this.map_ = map;
|
||||
if (!goog.isNull(this.map_)) {
|
||||
var target = goog.isDef(this.target_) ?
|
||||
this.target_ : map.getOverlayContainer();
|
||||
goog.dom.appendChild(target, this.element);
|
||||
if (this.handleMapPostrender !== goog.nullFunction) {
|
||||
this.listenerKeys.push(goog.events.listen(map,
|
||||
ol.MapEventType.POSTRENDER, this.handleMapPostrender, false, this));
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1 @@
|
||||
@exportFunction ol.control.defaults ol.control.DefaultsOptions ol.Collection
|
||||
@@ -0,0 +1,45 @@
|
||||
goog.provide('ol.control');
|
||||
|
||||
goog.require('ol.Collection');
|
||||
goog.require('ol.control.Attribution');
|
||||
goog.require('ol.control.Logo');
|
||||
goog.require('ol.control.Zoom');
|
||||
|
||||
|
||||
/**
|
||||
* @param {ol.control.DefaultsOptions=} opt_options Defaults options.
|
||||
* @return {ol.Collection} Controls.
|
||||
*/
|
||||
ol.control.defaults = function(opt_options) {
|
||||
|
||||
var options = goog.isDef(opt_options) ? opt_options : {};
|
||||
|
||||
var controls = new ol.Collection();
|
||||
|
||||
var attributionControl = goog.isDef(options.attribution) ?
|
||||
options.attribution : true;
|
||||
if (attributionControl) {
|
||||
var attributionControlOptions = goog.isDef(options.attributionOptions) ?
|
||||
options.attributionOptions : undefined;
|
||||
controls.push(new ol.control.Attribution(attributionControlOptions));
|
||||
}
|
||||
|
||||
var logoControl = goog.isDef(options.logo) ?
|
||||
options.logo : true;
|
||||
if (logoControl) {
|
||||
var logoControlOptions = goog.isDef(options.logoOptions) ?
|
||||
options.logoOptions : undefined;
|
||||
controls.push(new ol.control.Logo(logoControlOptions));
|
||||
}
|
||||
|
||||
var zoomControl = goog.isDef(options.zoom) ?
|
||||
options.zoom : true;
|
||||
if (zoomControl) {
|
||||
var zoomControlOptions = goog.isDef(options.zoomOptions) ?
|
||||
options.zoomOptions : undefined;
|
||||
controls.push(new ol.control.Zoom(zoomControlOptions));
|
||||
}
|
||||
|
||||
return controls;
|
||||
|
||||
};
|
||||
@@ -0,0 +1,84 @@
|
||||
goog.provide('ol.control.DragBox');
|
||||
|
||||
goog.require('goog.asserts');
|
||||
goog.require('goog.dom');
|
||||
goog.require('goog.dom.TagName');
|
||||
goog.require('goog.events');
|
||||
goog.require('goog.math.Size');
|
||||
goog.require('goog.style');
|
||||
goog.require('ol.Coordinate');
|
||||
goog.require('ol.MapBrowserEvent');
|
||||
goog.require('ol.MapBrowserEvent.EventType');
|
||||
goog.require('ol.Pixel');
|
||||
goog.require('ol.control.Control');
|
||||
|
||||
|
||||
/**
|
||||
* @typedef {{startCoordinate: ol.Coordinate}}
|
||||
*/
|
||||
ol.control.DragBoxOptions;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
* @extends {ol.control.Control}
|
||||
* @param {ol.control.DragBoxOptions} options Drag box options.
|
||||
*/
|
||||
ol.control.DragBox = function(options) {
|
||||
|
||||
var element = goog.dom.createDom(goog.dom.TagName.DIV, 'ol-dragbox');
|
||||
|
||||
/**
|
||||
* @type {ol.Pixel|undefined}
|
||||
* @private
|
||||
*/
|
||||
this.startPixel_ = null;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {ol.Coordinate}
|
||||
*/
|
||||
this.startCoordinate_ = options.startCoordinate;
|
||||
|
||||
goog.base(this, {
|
||||
element: element
|
||||
});
|
||||
|
||||
};
|
||||
goog.inherits(ol.control.DragBox, ol.control.Control);
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
ol.control.DragBox.prototype.setMap = function(map) {
|
||||
goog.base(this, 'setMap', map);
|
||||
if (!goog.isNull(map)) {
|
||||
this.startPixel_ = map.getPixelFromCoordinate(this.startCoordinate_);
|
||||
goog.asserts.assert(goog.isDef(this.startPixel_));
|
||||
goog.style.setPosition(this.element,
|
||||
this.startPixel_[0], this.startPixel_[1]);
|
||||
goog.style.setBorderBoxSize(this.element, new goog.math.Size(0, 0));
|
||||
this.listenerKeys.push(goog.events.listen(
|
||||
map, ol.MapBrowserEvent.EventType.DRAG, this.updateBox_, false, this));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {ol.MapBrowserEvent} mapBrowserEvent The event to handle.
|
||||
* @private
|
||||
*/
|
||||
ol.control.DragBox.prototype.updateBox_ = function(mapBrowserEvent) {
|
||||
var map = this.getMap();
|
||||
var coordinate = mapBrowserEvent.getCoordinate();
|
||||
goog.asserts.assert(goog.isDef(coordinate));
|
||||
var currentPixel = map.getPixelFromCoordinate(coordinate);
|
||||
goog.style.setPosition(this.element,
|
||||
Math.min(currentPixel[0], this.startPixel_[0]),
|
||||
Math.min(currentPixel[1], this.startPixel_[1]));
|
||||
goog.style.setBorderBoxSize(this.element, new goog.math.Size(
|
||||
Math.abs(currentPixel[0] - this.startPixel_[0]),
|
||||
Math.abs(currentPixel[1] - this.startPixel_[1])));
|
||||
};
|
||||
@@ -0,0 +1 @@
|
||||
@exportClass ol.control.FullScreen ol.control.FullScreenOptions
|
||||
@@ -0,0 +1,111 @@
|
||||
goog.provide('ol.control.FullScreen');
|
||||
|
||||
goog.require('goog.asserts');
|
||||
goog.require('goog.dom');
|
||||
goog.require('goog.dom.TagName');
|
||||
goog.require('goog.dom.classes');
|
||||
goog.require('goog.dom.fullscreen');
|
||||
goog.require('goog.dom.fullscreen.EventType');
|
||||
goog.require('goog.events');
|
||||
goog.require('goog.events.EventType');
|
||||
goog.require('ol.control.Control');
|
||||
goog.require('ol.css');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Provides a button that when clicked fills up the full screen with the map.
|
||||
* When in full screen mode, a close button is shown to exit full screen mode.
|
||||
* The [Fullscreen API](http://www.w3.org/TR/fullscreen/) is used to
|
||||
* toggle the map in full screen mode.
|
||||
*
|
||||
*
|
||||
* @constructor
|
||||
* @extends {ol.control.Control}
|
||||
* @param {ol.control.FullScreenOptions=} opt_options Options.
|
||||
*/
|
||||
ol.control.FullScreen = function(opt_options) {
|
||||
|
||||
var options = goog.isDef(opt_options) ? opt_options : {};
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {string}
|
||||
*/
|
||||
this.cssClassName_ = goog.isDef(options.className) ?
|
||||
options.className : 'ol-full-screen';
|
||||
|
||||
var aElement = goog.dom.createDom(goog.dom.TagName.A, {
|
||||
'href': '#fullScreen',
|
||||
'class': this.cssClassName_ + '-' + goog.dom.fullscreen.isFullScreen()
|
||||
});
|
||||
goog.events.listen(aElement, [
|
||||
goog.events.EventType.CLICK,
|
||||
goog.events.EventType.TOUCHEND
|
||||
], this.handleClick_, false, this);
|
||||
|
||||
goog.events.listen(goog.global.document, goog.dom.fullscreen.EventType.CHANGE,
|
||||
this.handleFullScreenChange_, false, this);
|
||||
|
||||
var element = goog.dom.createDom(goog.dom.TagName.DIV, {
|
||||
'class': this.cssClassName_ + ' ' + ol.css.CLASS_UNSELECTABLE + ' ' +
|
||||
(!goog.dom.fullscreen.isSupported() ? ol.css.CLASS_UNSUPPORTED : '')
|
||||
}, aElement);
|
||||
|
||||
goog.base(this, {
|
||||
element: element,
|
||||
target: options.target
|
||||
});
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.keys_ = goog.isDef(options.keys) ? options.keys : false;
|
||||
|
||||
};
|
||||
goog.inherits(ol.control.FullScreen, ol.control.Control);
|
||||
|
||||
|
||||
/**
|
||||
* @param {goog.events.BrowserEvent} browserEvent Browser event.
|
||||
* @private
|
||||
*/
|
||||
ol.control.FullScreen.prototype.handleClick_ = function(browserEvent) {
|
||||
if (!goog.dom.fullscreen.isSupported()) {
|
||||
return;
|
||||
}
|
||||
browserEvent.preventDefault();
|
||||
var map = this.getMap();
|
||||
if (goog.isNull(map)) {
|
||||
return;
|
||||
}
|
||||
if (goog.dom.fullscreen.isFullScreen()) {
|
||||
goog.dom.fullscreen.exitFullScreen();
|
||||
} else {
|
||||
var target = map.getTarget();
|
||||
goog.asserts.assert(goog.isDefAndNotNull(target));
|
||||
var element = goog.dom.getElement(target);
|
||||
goog.asserts.assert(goog.isDefAndNotNull(element));
|
||||
if (this.keys_) {
|
||||
goog.dom.fullscreen.requestFullScreenWithKeys(element);
|
||||
} else {
|
||||
goog.dom.fullscreen.requestFullScreen(element);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
ol.control.FullScreen.prototype.handleFullScreenChange_ = function() {
|
||||
var opened = this.cssClassName_ + '-true';
|
||||
var closed = this.cssClassName_ + '-false';
|
||||
var anchor = goog.dom.getFirstElementChild(this.element);
|
||||
if (goog.dom.fullscreen.isFullScreen()) {
|
||||
goog.dom.classes.swap(anchor, closed, opened);
|
||||
} else {
|
||||
goog.dom.classes.swap(anchor, opened, closed);
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,2 @@
|
||||
@exportClass ol.control.Logo ol.control.LogoOptions
|
||||
@exportProperty ol.control.Logo.prototype.setMap
|
||||
@@ -0,0 +1,110 @@
|
||||
goog.provide('ol.control.Logo');
|
||||
|
||||
goog.require('goog.dom');
|
||||
goog.require('goog.dom.TagName');
|
||||
goog.require('goog.object');
|
||||
goog.require('goog.style');
|
||||
goog.require('ol.FrameState');
|
||||
goog.require('ol.control.Control');
|
||||
goog.require('ol.css');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Shows a logo for all the layer sources in the map that have a logo
|
||||
* associated with them, such as Bing. This control is part of a default map.
|
||||
* By default it will show in the bottom-left portion of the map, but it can
|
||||
* be styled by using a css selector for .ol-logo.
|
||||
* @constructor
|
||||
* @extends {ol.control.Control}
|
||||
* @param {ol.control.LogoOptions=} opt_options Logo options.
|
||||
*/
|
||||
ol.control.Logo = function(opt_options) {
|
||||
|
||||
var options = goog.isDef(opt_options) ? opt_options : {};
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {Element}
|
||||
*/
|
||||
this.ulElement_ = goog.dom.createElement(goog.dom.TagName.UL);
|
||||
|
||||
var className = goog.isDef(options.className) ? options.className : 'ol-logo';
|
||||
|
||||
var element = goog.dom.createDom(goog.dom.TagName.DIV, {
|
||||
'class': className + ' ' + ol.css.CLASS_UNSELECTABLE
|
||||
}, this.ulElement_);
|
||||
|
||||
goog.base(this, {
|
||||
element: element,
|
||||
target: options.target
|
||||
});
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.renderedVisible_ = true;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {Object.<string, Element>}
|
||||
*/
|
||||
this.logoElements_ = {};
|
||||
|
||||
};
|
||||
goog.inherits(ol.control.Logo, ol.control.Control);
|
||||
|
||||
|
||||
/**
|
||||
* @param {ol.MapEvent} mapEvent Map event.
|
||||
*/
|
||||
ol.control.Logo.prototype.handleMapPostrender = function(mapEvent) {
|
||||
this.updateElement_(mapEvent.frameState);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {?ol.FrameState} frameState Frame state.
|
||||
* @private
|
||||
*/
|
||||
ol.control.Logo.prototype.updateElement_ = function(frameState) {
|
||||
|
||||
if (goog.isNull(frameState)) {
|
||||
if (this.renderedVisible_) {
|
||||
goog.style.setElementShown(this.element, false);
|
||||
this.renderedVisible_ = false;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
var logo;
|
||||
var logos = frameState.logos;
|
||||
var logoElements = this.logoElements_;
|
||||
|
||||
for (logo in logoElements) {
|
||||
if (!(logo in logos)) {
|
||||
goog.dom.removeNode(logoElements[logo]);
|
||||
delete logoElements[logo];
|
||||
}
|
||||
}
|
||||
|
||||
var image, logoElement;
|
||||
for (logo in logos) {
|
||||
if (!(logo in logoElements)) {
|
||||
image = new Image();
|
||||
image.src = logo;
|
||||
logoElement = goog.dom.createElement(goog.dom.TagName.LI);
|
||||
logoElement.appendChild(image);
|
||||
goog.dom.appendChild(this.ulElement_, logoElement);
|
||||
logoElements[logo] = logoElement;
|
||||
}
|
||||
}
|
||||
|
||||
var renderVisible = !goog.object.isEmpty(logos);
|
||||
if (this.renderedVisible_ != renderVisible) {
|
||||
goog.style.setElementShown(this.element, renderVisible);
|
||||
this.renderedVisible_ = renderVisible;
|
||||
}
|
||||
|
||||
};
|
||||
@@ -0,0 +1,2 @@
|
||||
@exportClass ol.control.MousePosition ol.control.MousePositionOptions
|
||||
@exportProperty ol.control.MousePosition.prototype.setMap
|
||||
@@ -0,0 +1,250 @@
|
||||
// FIXME should listen on appropriate pane, once it is defined
|
||||
// FIXME works for View2D only
|
||||
|
||||
goog.provide('ol.control.MousePosition');
|
||||
|
||||
goog.require('goog.array');
|
||||
goog.require('goog.dom');
|
||||
goog.require('goog.dom.TagName');
|
||||
goog.require('goog.events');
|
||||
goog.require('goog.events.EventType');
|
||||
goog.require('goog.style');
|
||||
goog.require('ol.CoordinateFormatType');
|
||||
goog.require('ol.Object');
|
||||
goog.require('ol.Pixel');
|
||||
goog.require('ol.Projection');
|
||||
goog.require('ol.TransformFunction');
|
||||
goog.require('ol.control.Control');
|
||||
goog.require('ol.proj');
|
||||
|
||||
|
||||
/**
|
||||
* @enum {string}
|
||||
*/
|
||||
ol.control.MousePositionProperty = {
|
||||
PROJECTION: 'projection',
|
||||
COORDINATE_FORMAT: 'coordinateFormat'
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Create a new control to show the position of the mouse in the map's
|
||||
* projection (or any other supplied projection). By default the control is
|
||||
* shown in the top right corner of the map but this can be changed by using
|
||||
* a css selector .ol-mouse-position.
|
||||
*
|
||||
* @constructor
|
||||
* @extends {ol.control.Control}
|
||||
* @param {ol.control.MousePositionOptions=} opt_options Mouse position options.
|
||||
*/
|
||||
ol.control.MousePosition = function(opt_options) {
|
||||
|
||||
var options = goog.isDef(opt_options) ? opt_options : {};
|
||||
|
||||
var className = goog.isDef(options.className) ?
|
||||
options.className : 'ol-mouse-position';
|
||||
|
||||
var element = goog.dom.createDom(goog.dom.TagName.DIV, {
|
||||
'class': className
|
||||
});
|
||||
|
||||
goog.base(this, {
|
||||
element: element,
|
||||
target: options.target
|
||||
});
|
||||
|
||||
goog.events.listen(this,
|
||||
ol.Object.getChangeEventType(ol.control.MousePositionProperty.PROJECTION),
|
||||
this.handleProjectionChanged_, false, this);
|
||||
|
||||
if (goog.isDef(options.coordinateFormat)) {
|
||||
this.setCoordinateFormat(options.coordinateFormat);
|
||||
}
|
||||
if (goog.isDef(options.projection)) {
|
||||
this.setProjection(ol.proj.get(options.projection));
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {string}
|
||||
*/
|
||||
this.undefinedHTML_ = goog.isDef(options.undefinedHTML) ?
|
||||
options.undefinedHTML : '';
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {string}
|
||||
*/
|
||||
this.renderedHTML_ = element.innerHTML;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {ol.Projection}
|
||||
*/
|
||||
this.mapProjection_ = null;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {?ol.TransformFunction}
|
||||
*/
|
||||
this.transform_ = null;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {ol.Pixel}
|
||||
*/
|
||||
this.lastMouseMovePixel_ = null;
|
||||
|
||||
};
|
||||
goog.inherits(ol.control.MousePosition, ol.control.Control);
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
ol.control.MousePosition.prototype.handleMapPostrender = function(mapEvent) {
|
||||
var frameState = mapEvent.frameState;
|
||||
if (goog.isNull(frameState)) {
|
||||
this.mapProjection_ = null;
|
||||
} else {
|
||||
if (this.mapProjection_ != frameState.view2DState.projection) {
|
||||
this.mapProjection_ = frameState.view2DState.projection;
|
||||
this.transform_ = null;
|
||||
}
|
||||
}
|
||||
this.updateHTML_(this.lastMouseMovePixel_);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
ol.control.MousePosition.prototype.handleProjectionChanged_ = function() {
|
||||
this.transform_ = null;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {ol.CoordinateFormatType|undefined} projection.
|
||||
*/
|
||||
ol.control.MousePosition.prototype.getCoordinateFormat = function() {
|
||||
return /** @type {ol.CoordinateFormatType|undefined} */ (
|
||||
this.get(ol.control.MousePositionProperty.COORDINATE_FORMAT));
|
||||
};
|
||||
goog.exportProperty(
|
||||
ol.control.MousePosition.prototype,
|
||||
'getCoordinateFormat',
|
||||
ol.control.MousePosition.prototype.getCoordinateFormat);
|
||||
|
||||
|
||||
/**
|
||||
* @return {ol.Projection|undefined} projection.
|
||||
*/
|
||||
ol.control.MousePosition.prototype.getProjection = function() {
|
||||
return /** @type {ol.Projection|undefined} */ (
|
||||
this.get(ol.control.MousePositionProperty.PROJECTION));
|
||||
};
|
||||
goog.exportProperty(
|
||||
ol.control.MousePosition.prototype,
|
||||
'getProjection',
|
||||
ol.control.MousePosition.prototype.getProjection);
|
||||
|
||||
|
||||
/**
|
||||
* @param {goog.events.BrowserEvent} browserEvent Browser event.
|
||||
* @protected
|
||||
*/
|
||||
ol.control.MousePosition.prototype.handleMouseMove = function(browserEvent) {
|
||||
var map = this.getMap();
|
||||
var eventPosition = goog.style.getRelativePosition(
|
||||
browserEvent, map.getViewport());
|
||||
this.lastMouseMovePixel_ = [eventPosition.x, eventPosition.y];
|
||||
this.updateHTML_(this.lastMouseMovePixel_);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {goog.events.BrowserEvent} browserEvent Browser event.
|
||||
* @protected
|
||||
*/
|
||||
ol.control.MousePosition.prototype.handleMouseOut = function(browserEvent) {
|
||||
this.updateHTML_(null);
|
||||
this.lastMouseMovePixel_ = null;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
ol.control.MousePosition.prototype.setMap = function(map) {
|
||||
goog.base(this, 'setMap', map);
|
||||
if (!goog.isNull(map)) {
|
||||
var viewport = map.getViewport();
|
||||
this.listenerKeys.push(
|
||||
goog.events.listen(viewport, goog.events.EventType.MOUSEMOVE,
|
||||
this.handleMouseMove, false, this),
|
||||
goog.events.listen(viewport, goog.events.EventType.MOUSEOUT,
|
||||
this.handleMouseOut, false, this)
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {ol.CoordinateFormatType} format Coordinate format.
|
||||
*/
|
||||
ol.control.MousePosition.prototype.setCoordinateFormat = function(format) {
|
||||
this.set(ol.control.MousePositionProperty.COORDINATE_FORMAT, format);
|
||||
};
|
||||
goog.exportProperty(
|
||||
ol.control.MousePosition.prototype,
|
||||
'setCoordinateFormat',
|
||||
ol.control.MousePosition.prototype.setCoordinateFormat);
|
||||
|
||||
|
||||
/**
|
||||
* @param {ol.Projection} projection Projection.
|
||||
*/
|
||||
ol.control.MousePosition.prototype.setProjection = function(projection) {
|
||||
this.set(ol.control.MousePositionProperty.PROJECTION, projection);
|
||||
};
|
||||
goog.exportProperty(
|
||||
ol.control.MousePosition.prototype,
|
||||
'setProjection',
|
||||
ol.control.MousePosition.prototype.setProjection);
|
||||
|
||||
|
||||
/**
|
||||
* @param {?ol.Pixel} pixel Pixel.
|
||||
* @private
|
||||
*/
|
||||
ol.control.MousePosition.prototype.updateHTML_ = function(pixel) {
|
||||
var html = this.undefinedHTML_;
|
||||
if (!goog.isNull(pixel) && !goog.isNull(this.mapProjection_)) {
|
||||
if (goog.isNull(this.transform_)) {
|
||||
var projection = this.getProjection();
|
||||
if (goog.isDef(projection)) {
|
||||
this.transform_ = ol.proj.getTransformFromProjections(
|
||||
this.mapProjection_, projection);
|
||||
} else {
|
||||
this.transform_ = ol.proj.identityTransform;
|
||||
}
|
||||
}
|
||||
var map = this.getMap();
|
||||
var coordinate = map.getCoordinateFromPixel(pixel);
|
||||
if (!goog.isNull(coordinate)) {
|
||||
this.transform_(coordinate, coordinate);
|
||||
var coordinateFormat = this.getCoordinateFormat();
|
||||
if (goog.isDef(coordinateFormat)) {
|
||||
html = coordinateFormat(coordinate);
|
||||
} else {
|
||||
html = coordinate.toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!goog.isDef(this.renderedHTML_) || html != this.renderedHTML_) {
|
||||
this.element.innerHTML = html;
|
||||
this.renderedHTML_ = html;
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,9 @@
|
||||
@exportClass ol.control.ScaleLine ol.control.ScaleLineOptions
|
||||
@exportProperty ol.control.ScaleLine.prototype.setMap
|
||||
|
||||
@exportSymbol ol.control.ScaleLineUnits
|
||||
@exportProperty ol.control.ScaleLineUnits.DEGREES
|
||||
@exportProperty ol.control.ScaleLineUnits.IMPERIAL
|
||||
@exportProperty ol.control.ScaleLineUnits.NAUTICAL
|
||||
@exportProperty ol.control.ScaleLineUnits.METRIC
|
||||
@exportProperty ol.control.ScaleLineUnits.US
|
||||
@@ -0,0 +1,318 @@
|
||||
goog.provide('ol.control.ScaleLine');
|
||||
goog.provide('ol.control.ScaleLineProperty');
|
||||
goog.provide('ol.control.ScaleLineUnits');
|
||||
|
||||
goog.require('goog.array');
|
||||
goog.require('goog.asserts');
|
||||
goog.require('goog.dom');
|
||||
goog.require('goog.dom.TagName');
|
||||
goog.require('goog.events');
|
||||
goog.require('goog.math');
|
||||
goog.require('goog.style');
|
||||
goog.require('ol.Object');
|
||||
goog.require('ol.ProjectionUnits');
|
||||
goog.require('ol.TransformFunction');
|
||||
goog.require('ol.View2DState');
|
||||
goog.require('ol.control.Control');
|
||||
goog.require('ol.css');
|
||||
goog.require('ol.proj');
|
||||
goog.require('ol.sphere.NORMAL');
|
||||
|
||||
|
||||
/**
|
||||
* @enum {string}
|
||||
*/
|
||||
ol.control.ScaleLineProperty = {
|
||||
UNITS: 'units'
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @enum {string}
|
||||
*/
|
||||
ol.control.ScaleLineUnits = {
|
||||
DEGREES: 'degrees',
|
||||
IMPERIAL: 'imperial',
|
||||
NAUTICAL: 'nautical',
|
||||
METRIC: 'metric',
|
||||
US: 'us'
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Create a control to help users estimate distances on a map.
|
||||
*
|
||||
* @constructor
|
||||
* @extends {ol.control.Control}
|
||||
* @param {ol.control.ScaleLineOptions=} opt_options Scale line options.
|
||||
*/
|
||||
ol.control.ScaleLine = function(opt_options) {
|
||||
|
||||
var options = opt_options || {};
|
||||
|
||||
var className = goog.isDef(options.className) ?
|
||||
options.className : 'ol-scale-line';
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {Element}
|
||||
*/
|
||||
this.innerElement_ = goog.dom.createDom(goog.dom.TagName.DIV, {
|
||||
'class': className + '-inner'
|
||||
});
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {Element}
|
||||
*/
|
||||
this.element_ = goog.dom.createDom(goog.dom.TagName.DIV, {
|
||||
'class': className + ' ' + ol.css.CLASS_UNSELECTABLE
|
||||
}, this.innerElement_);
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {?ol.View2DState}
|
||||
*/
|
||||
this.view2DState_ = null;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {number}
|
||||
*/
|
||||
this.minWidth_ = goog.isDef(options.minWidth) ? options.minWidth : 64;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.renderedVisible_ = false;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {number|undefined}
|
||||
*/
|
||||
this.renderedWidth_ = undefined;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {string}
|
||||
*/
|
||||
this.renderedHTML_ = '';
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {?ol.TransformFunction}
|
||||
*/
|
||||
this.toEPSG4326_ = null;
|
||||
|
||||
goog.base(this, {
|
||||
element: this.element_,
|
||||
target: options.target
|
||||
});
|
||||
|
||||
goog.events.listen(
|
||||
this, ol.Object.getChangeEventType(ol.control.ScaleLineProperty.UNITS),
|
||||
this.handleUnitsChanged_, false, this);
|
||||
|
||||
this.setUnits(options.units || ol.control.ScaleLineUnits.METRIC);
|
||||
|
||||
};
|
||||
goog.inherits(ol.control.ScaleLine, ol.control.Control);
|
||||
|
||||
|
||||
/**
|
||||
* @const
|
||||
* @type {Array.<number>}
|
||||
*/
|
||||
ol.control.ScaleLine.LEADING_DIGITS = [1, 2, 5];
|
||||
|
||||
|
||||
/**
|
||||
* @return {ol.control.ScaleLineUnits|undefined} units.
|
||||
*/
|
||||
ol.control.ScaleLine.prototype.getUnits = function() {
|
||||
return /** @type {ol.control.ScaleLineUnits|undefined} */ (
|
||||
this.get(ol.control.ScaleLineProperty.UNITS));
|
||||
};
|
||||
goog.exportProperty(
|
||||
ol.control.ScaleLine.prototype,
|
||||
'getUnits',
|
||||
ol.control.ScaleLine.prototype.getUnits);
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
ol.control.ScaleLine.prototype.handleMapPostrender = function(mapEvent) {
|
||||
var frameState = mapEvent.frameState;
|
||||
if (goog.isNull(frameState)) {
|
||||
this.view2DState_ = null;
|
||||
} else {
|
||||
this.view2DState_ = frameState.view2DState;
|
||||
}
|
||||
this.updateElement_();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
ol.control.ScaleLine.prototype.handleUnitsChanged_ = function() {
|
||||
this.updateElement_();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {ol.control.ScaleLineUnits} units Units.
|
||||
*/
|
||||
ol.control.ScaleLine.prototype.setUnits = function(units) {
|
||||
this.set(ol.control.ScaleLineProperty.UNITS, units);
|
||||
};
|
||||
goog.exportProperty(
|
||||
ol.control.ScaleLine.prototype,
|
||||
'setUnits',
|
||||
ol.control.ScaleLine.prototype.setUnits);
|
||||
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
ol.control.ScaleLine.prototype.updateElement_ = function() {
|
||||
var view2DState = this.view2DState_;
|
||||
|
||||
if (goog.isNull(view2DState)) {
|
||||
if (this.renderedVisible_) {
|
||||
goog.style.setElementShown(this.element_, false);
|
||||
this.renderedVisible_ = false;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
var center = view2DState.center;
|
||||
var projection = view2DState.projection;
|
||||
var pointResolution =
|
||||
projection.getPointResolution(view2DState.resolution, center);
|
||||
var projectionUnits = projection.getUnits();
|
||||
|
||||
var cosLatitude;
|
||||
var units = this.getUnits();
|
||||
if (projectionUnits == ol.ProjectionUnits.DEGREES &&
|
||||
(units == ol.control.ScaleLineUnits.METRIC ||
|
||||
units == ol.control.ScaleLineUnits.IMPERIAL)) {
|
||||
|
||||
// Convert pointResolution from degrees to meters
|
||||
this.toEPSG4326_ = null;
|
||||
cosLatitude = Math.cos(goog.math.toRadians(center[1]));
|
||||
pointResolution *= Math.PI * cosLatitude * ol.sphere.NORMAL.radius / 180;
|
||||
projectionUnits = ol.ProjectionUnits.METERS;
|
||||
|
||||
} else if ((projectionUnits == ol.ProjectionUnits.FEET ||
|
||||
projectionUnits == ol.ProjectionUnits.METERS) &&
|
||||
units == ol.control.ScaleLineUnits.DEGREES) {
|
||||
|
||||
// Convert pointResolution from meters or feet to degrees
|
||||
if (goog.isNull(this.toEPSG4326_)) {
|
||||
this.toEPSG4326_ = ol.proj.getTransformFromProjections(
|
||||
projection, ol.proj.get('EPSG:4326'));
|
||||
}
|
||||
cosLatitude = Math.cos(goog.math.toRadians(this.toEPSG4326_(center)[1]));
|
||||
var radius = ol.sphere.NORMAL.radius;
|
||||
if (projectionUnits == ol.ProjectionUnits.FEET) {
|
||||
radius /= 0.3048;
|
||||
}
|
||||
pointResolution *= 180 / (Math.PI * cosLatitude * radius);
|
||||
projectionUnits = ol.ProjectionUnits.DEGREES;
|
||||
|
||||
} else {
|
||||
this.toEPSG4326_ = null;
|
||||
}
|
||||
|
||||
goog.asserts.assert(
|
||||
((units == ol.control.ScaleLineUnits.METRIC ||
|
||||
units == ol.control.ScaleLineUnits.IMPERIAL) &&
|
||||
projectionUnits == ol.ProjectionUnits.METERS) ||
|
||||
(units == ol.control.ScaleLineUnits.DEGREES &&
|
||||
projectionUnits == ol.ProjectionUnits.DEGREES));
|
||||
|
||||
var nominalCount = this.minWidth_ * pointResolution;
|
||||
var suffix = '';
|
||||
if (units == ol.control.ScaleLineUnits.DEGREES) {
|
||||
if (nominalCount < 1 / 60) {
|
||||
suffix = '\u2033'; // seconds
|
||||
pointResolution *= 3600;
|
||||
} else if (nominalCount < 1) {
|
||||
suffix = '\u2032'; // minutes
|
||||
pointResolution *= 60;
|
||||
} else {
|
||||
suffix = '\u00b0'; // degrees
|
||||
}
|
||||
} else if (units == ol.control.ScaleLineUnits.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 == ol.control.ScaleLineUnits.NAUTICAL) {
|
||||
pointResolution /= 1852;
|
||||
suffix = 'nm';
|
||||
} else if (units == ol.control.ScaleLineUnits.METRIC) {
|
||||
if (nominalCount < 1) {
|
||||
suffix = 'mm';
|
||||
pointResolution *= 1000;
|
||||
} else if (nominalCount < 1000) {
|
||||
suffix = 'm';
|
||||
} else {
|
||||
suffix = 'km';
|
||||
pointResolution /= 1000;
|
||||
}
|
||||
} else if (units == ol.control.ScaleLineUnits.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 {
|
||||
goog.asserts.fail();
|
||||
}
|
||||
|
||||
var i = 3 * Math.floor(
|
||||
Math.log(this.minWidth_ * pointResolution) / Math.log(10));
|
||||
var count, width;
|
||||
while (true) {
|
||||
count = ol.control.ScaleLine.LEADING_DIGITS[i % 3] *
|
||||
Math.pow(10, Math.floor(i / 3));
|
||||
width = Math.round(count / pointResolution);
|
||||
if (width >= this.minWidth_) {
|
||||
break;
|
||||
}
|
||||
++i;
|
||||
}
|
||||
|
||||
var 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_) {
|
||||
goog.style.setElementShown(this.element_, true);
|
||||
this.renderedVisible_ = true;
|
||||
}
|
||||
|
||||
};
|
||||
@@ -0,0 +1,2 @@
|
||||
@exportClass ol.control.Zoom ol.control.ZoomOptions
|
||||
@exportProperty ol.control.Zoom.prototype.setMap
|
||||
@@ -0,0 +1,90 @@
|
||||
// FIXME works for View2D only
|
||||
|
||||
goog.provide('ol.control.Zoom');
|
||||
|
||||
goog.require('goog.dom');
|
||||
goog.require('goog.dom.TagName');
|
||||
goog.require('goog.events');
|
||||
goog.require('goog.events.EventType');
|
||||
goog.require('ol.animation');
|
||||
goog.require('ol.control.Control');
|
||||
goog.require('ol.css');
|
||||
goog.require('ol.easing');
|
||||
|
||||
|
||||
/**
|
||||
* @define {number} Zoom duration.
|
||||
*/
|
||||
ol.control.ZOOM_DURATION = 250;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Create a new control with 2 buttons, one for zoom in and one for zoom out.
|
||||
* This control is part of the default controls of a map. To style this control
|
||||
* use css selectors .ol-zoom-in and .ol-zoom-out.
|
||||
* @constructor
|
||||
* @extends {ol.control.Control}
|
||||
* @param {ol.control.ZoomOptions=} opt_options Zoom options.
|
||||
*/
|
||||
ol.control.Zoom = function(opt_options) {
|
||||
|
||||
var options = goog.isDef(opt_options) ? opt_options : {};
|
||||
|
||||
var className = goog.isDef(options.className) ? options.className : 'ol-zoom';
|
||||
|
||||
var delta = goog.isDef(options.delta) ? options.delta : 1;
|
||||
|
||||
var inElement = goog.dom.createDom(goog.dom.TagName.A, {
|
||||
'href': '#zoomIn',
|
||||
'class': className + '-in'
|
||||
});
|
||||
goog.events.listen(inElement, [
|
||||
goog.events.EventType.TOUCHEND,
|
||||
goog.events.EventType.CLICK
|
||||
], goog.partial(ol.control.Zoom.prototype.zoomByDelta_, delta), false, this);
|
||||
|
||||
var outElement = goog.dom.createDom(goog.dom.TagName.A, {
|
||||
'href': '#zoomOut',
|
||||
'class': className + '-out'
|
||||
});
|
||||
goog.events.listen(outElement, [
|
||||
goog.events.EventType.TOUCHEND,
|
||||
goog.events.EventType.CLICK
|
||||
], goog.partial(ol.control.Zoom.prototype.zoomByDelta_, -delta), false, this);
|
||||
|
||||
var cssClasses = className + ' ' + ol.css.CLASS_UNSELECTABLE;
|
||||
var element = goog.dom.createDom(goog.dom.TagName.DIV, cssClasses, inElement,
|
||||
outElement);
|
||||
|
||||
goog.base(this, {
|
||||
element: element,
|
||||
target: options.target
|
||||
});
|
||||
|
||||
};
|
||||
goog.inherits(ol.control.Zoom, ol.control.Control);
|
||||
|
||||
|
||||
/**
|
||||
* @param {number} delta Zoom delta.
|
||||
* @param {goog.events.BrowserEvent} browserEvent The browser event to handle.
|
||||
* @private
|
||||
*/
|
||||
ol.control.Zoom.prototype.zoomByDelta_ = function(delta, browserEvent) {
|
||||
// prevent the anchor from getting appended to the url
|
||||
browserEvent.preventDefault();
|
||||
var map = this.getMap();
|
||||
// FIXME works for View2D only
|
||||
var view = map.getView().getView2D();
|
||||
var currentResolution = view.getResolution();
|
||||
if (goog.isDef(currentResolution)) {
|
||||
map.beforeRender(ol.animation.zoom({
|
||||
resolution: currentResolution,
|
||||
duration: ol.control.ZOOM_DURATION,
|
||||
easing: ol.easing.easeOut
|
||||
}));
|
||||
var newResolution = view.constrainResolution(currentResolution, delta);
|
||||
view.setResolution(newResolution);
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1 @@
|
||||
@exportClass ol.control.ZoomSlider ol.control.ZoomSliderOptions
|
||||
@@ -0,0 +1,310 @@
|
||||
// FIXME works for View2D only
|
||||
// FIXME should possibly show tooltip when dragging?
|
||||
// FIXME should possibly be adjustable by clicking on container
|
||||
|
||||
goog.provide('ol.control.ZoomSlider');
|
||||
|
||||
goog.require('goog.array');
|
||||
goog.require('goog.asserts');
|
||||
goog.require('goog.dom');
|
||||
goog.require('goog.dom.TagName');
|
||||
goog.require('goog.events');
|
||||
goog.require('goog.events.EventType');
|
||||
goog.require('goog.fx.Dragger');
|
||||
goog.require('goog.fx.Dragger.EventType');
|
||||
goog.require('goog.math');
|
||||
goog.require('goog.math.Rect');
|
||||
goog.require('goog.style');
|
||||
goog.require('ol.animation');
|
||||
goog.require('ol.control.Control');
|
||||
goog.require('ol.css');
|
||||
goog.require('ol.easing');
|
||||
|
||||
|
||||
/**
|
||||
* @define {number} Animation duration.
|
||||
*/
|
||||
ol.control.ZOOMSLIDER_ANIMATION_DURATION = 200;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* A slider type of control for zooming.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* map.addControl(new ol.control.ZoomSlider());
|
||||
*
|
||||
* @constructor
|
||||
* @extends {ol.control.Control}
|
||||
* @param {ol.control.ZoomSliderOptions=} opt_options Zoom slider options.
|
||||
*/
|
||||
ol.control.ZoomSlider = function(opt_options) {
|
||||
|
||||
var options = goog.isDef(opt_options) ? opt_options : {};
|
||||
|
||||
/**
|
||||
* Will hold the current resolution of the view.
|
||||
*
|
||||
* @type {number|undefined}
|
||||
* @private
|
||||
*/
|
||||
this.currentResolution_ = undefined;
|
||||
|
||||
/**
|
||||
* The direction of the slider. Will be determined from actual display of the
|
||||
* container and defaults to ol.control.ZoomSlider.direction.VERTICAL.
|
||||
*
|
||||
* @type {ol.control.ZoomSlider.direction}
|
||||
* @private
|
||||
*/
|
||||
this.direction_ = ol.control.ZoomSlider.direction.VERTICAL;
|
||||
|
||||
/**
|
||||
* Whether the slider is initialized.
|
||||
* @type {boolean}
|
||||
* @private
|
||||
*/
|
||||
this.sliderInitialized_ = false;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {Array.<?number>}
|
||||
*/
|
||||
this.draggerListenerKeys_ = null;
|
||||
|
||||
var className = goog.isDef(options.className) ?
|
||||
options.className : 'ol-zoomslider';
|
||||
var sliderCssCls = className + ' ' + ol.css.CLASS_UNSELECTABLE;
|
||||
var thumbCssCls = className + '-thumb' + ' ' + ol.css.CLASS_UNSELECTABLE;
|
||||
var element = goog.dom.createDom(goog.dom.TagName.DIV, sliderCssCls,
|
||||
goog.dom.createDom(goog.dom.TagName.DIV, thumbCssCls));
|
||||
|
||||
this.dragger_ = this.createDraggable_(element);
|
||||
|
||||
// FIXME currently only a do nothing function is bound.
|
||||
goog.events.listen(element, [
|
||||
goog.events.EventType.TOUCHEND,
|
||||
goog.events.EventType.CLICK
|
||||
], this.handleContainerClick_, false, this);
|
||||
|
||||
goog.base(this, {
|
||||
element: element
|
||||
});
|
||||
};
|
||||
goog.inherits(ol.control.ZoomSlider, ol.control.Control);
|
||||
|
||||
|
||||
/**
|
||||
* The enum for available directions.
|
||||
*
|
||||
* @enum {number}
|
||||
*/
|
||||
ol.control.ZoomSlider.direction = {
|
||||
VERTICAL: 0,
|
||||
HORIZONTAL: 1
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
ol.control.ZoomSlider.prototype.setMap = function(map) {
|
||||
goog.base(this, 'setMap', map);
|
||||
if (!goog.isNull(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
|
||||
*/
|
||||
ol.control.ZoomSlider.prototype.initSlider_ = function() {
|
||||
var container = this.element,
|
||||
thumb = goog.dom.getFirstElementChild(container),
|
||||
elemSize = goog.style.getContentBoxSize(container),
|
||||
thumbBounds = goog.style.getBounds(thumb),
|
||||
thumbMargins = goog.style.getMarginBox(thumb),
|
||||
thumbBorderBox = goog.style.getBorderBox(thumb),
|
||||
w = elemSize.width -
|
||||
thumbMargins.left - thumbMargins.right -
|
||||
thumbBorderBox.left - thumbBorderBox.right -
|
||||
thumbBounds.width,
|
||||
h = elemSize.height -
|
||||
thumbMargins.top - thumbMargins.bottom -
|
||||
thumbBorderBox.top - thumbBorderBox.bottom -
|
||||
thumbBounds.height,
|
||||
limits;
|
||||
if (elemSize.width > elemSize.height) {
|
||||
this.direction_ = ol.control.ZoomSlider.direction.HORIZONTAL;
|
||||
limits = new goog.math.Rect(0, 0, w, 0);
|
||||
} else {
|
||||
this.direction_ = ol.control.ZoomSlider.direction.VERTICAL;
|
||||
limits = new goog.math.Rect(0, 0, 0, h);
|
||||
}
|
||||
this.dragger_.setLimits(limits);
|
||||
this.sliderInitialized_ = true;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
ol.control.ZoomSlider.prototype.handleMapPostrender = function(mapEvent) {
|
||||
if (goog.isNull(mapEvent.frameState)) {
|
||||
return;
|
||||
}
|
||||
goog.asserts.assert(
|
||||
goog.isDefAndNotNull(mapEvent.frameState.view2DState));
|
||||
if (!this.sliderInitialized_) {
|
||||
this.initSlider_();
|
||||
}
|
||||
var res = mapEvent.frameState.view2DState.resolution;
|
||||
if (res !== this.currentResolution_) {
|
||||
this.currentResolution_ = res;
|
||||
this.positionThumbForResolution_(res);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {goog.events.BrowserEvent} browserEvent The browser event to handle.
|
||||
* @private
|
||||
*/
|
||||
ol.control.ZoomSlider.prototype.handleContainerClick_ = function(browserEvent) {
|
||||
// TODO implement proper resolution calculation according to browserEvent
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Positions the thumb inside its container according to the given resolution.
|
||||
*
|
||||
* @param {number} res The res.
|
||||
* @private
|
||||
*/
|
||||
ol.control.ZoomSlider.prototype.positionThumbForResolution_ = function(res) {
|
||||
var amount = this.amountForResolution_(res),
|
||||
dragger = this.dragger_,
|
||||
thumb = goog.dom.getFirstElementChild(this.element);
|
||||
|
||||
if (this.direction_ == ol.control.ZoomSlider.direction.HORIZONTAL) {
|
||||
var left = dragger.limits.left + dragger.limits.width * amount;
|
||||
goog.style.setPosition(thumb, left);
|
||||
} else {
|
||||
var top = dragger.limits.top + dragger.limits.height * amount;
|
||||
goog.style.setPosition(thumb, dragger.limits.left, top);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Calculates the amount the thumb has been dragged to allow for calculation
|
||||
* of the corresponding resolution.
|
||||
*
|
||||
* @param {goog.fx.DragDropEvent} e The dragdropevent.
|
||||
* @return {number} The amount the thumb has been dragged.
|
||||
* @private
|
||||
*/
|
||||
ol.control.ZoomSlider.prototype.amountDragged_ = function(e) {
|
||||
var draggerLimits = this.dragger_.limits,
|
||||
amount = 0;
|
||||
if (this.direction_ === ol.control.ZoomSlider.direction.HORIZONTAL) {
|
||||
amount = (e.left - draggerLimits.left) / draggerLimits.width;
|
||||
} else {
|
||||
amount = (e.top - draggerLimits.top) / draggerLimits.height;
|
||||
}
|
||||
return amount;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Calculates the corresponding resolution of the thumb by the amount it has
|
||||
* been dragged from its minimum.
|
||||
*
|
||||
* @param {number} amount The amount the thumb has been dragged.
|
||||
* @return {number} The corresponding resolution.
|
||||
* @private
|
||||
*/
|
||||
ol.control.ZoomSlider.prototype.resolutionForAmount_ = function(amount) {
|
||||
// FIXME do we really need this affine transform?
|
||||
amount = (goog.math.clamp(amount, 0, 1) - 1) * -1;
|
||||
var fn = this.getMap().getView().getView2D().getResolutionForValueFunction();
|
||||
return fn(amount);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Determines an amount of dragging relative to this minimum position by the
|
||||
* given resolution.
|
||||
*
|
||||
* @param {number} res The resolution to get the amount for.
|
||||
* @return {number} The corresponding value (between 0 and 1).
|
||||
* @private
|
||||
*/
|
||||
ol.control.ZoomSlider.prototype.amountForResolution_ = function(res) {
|
||||
var fn = this.getMap().getView().getView2D().getValueForResolutionFunction();
|
||||
var value = fn(res);
|
||||
// FIXME do we really need this affine transform?
|
||||
return (value - 1) * -1;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Handles the user caused changes of the slider thumb and adjusts the
|
||||
* resolution of our map accordingly. Will be called both while dragging and
|
||||
* when dragging ends.
|
||||
*
|
||||
* @param {goog.fx.DragDropEvent} e The dragdropevent.
|
||||
* @private
|
||||
*/
|
||||
ol.control.ZoomSlider.prototype.handleSliderChange_ = function(e) {
|
||||
var map = this.getMap();
|
||||
var view = map.getView().getView2D();
|
||||
var resolution;
|
||||
if (e.type === goog.fx.Dragger.EventType.DRAG) {
|
||||
var amountDragged = this.amountDragged_(e);
|
||||
resolution = this.resolutionForAmount_(amountDragged);
|
||||
if (resolution !== this.currentResolution_) {
|
||||
this.currentResolution_ = resolution;
|
||||
view.setResolution(resolution);
|
||||
}
|
||||
} else {
|
||||
goog.asserts.assert(goog.isDef(this.currentResolution_));
|
||||
map.beforeRender(ol.animation.zoom({
|
||||
resolution: this.currentResolution_,
|
||||
duration: ol.control.ZOOMSLIDER_ANIMATION_DURATION,
|
||||
easing: ol.easing.easeOut
|
||||
}));
|
||||
resolution = view.constrainResolution(this.currentResolution_);
|
||||
view.setResolution(resolution);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Actually enable draggable behaviour for the thumb of the zoomslider and bind
|
||||
* relvant event listeners.
|
||||
*
|
||||
* @param {Element} elem The element for the slider.
|
||||
* @return {goog.fx.Dragger} The actual goog.fx.Dragger instance.
|
||||
* @private
|
||||
*/
|
||||
ol.control.ZoomSlider.prototype.createDraggable_ = function(elem) {
|
||||
if (!goog.isNull(this.draggerListenerKeys_)) {
|
||||
goog.array.forEach(this.draggerListenerKeys_, goog.events.unlistenByKey);
|
||||
this.draggerListenerKeys_ = null;
|
||||
}
|
||||
var dragger = new goog.fx.Dragger(elem.childNodes[0]);
|
||||
this.draggerListenerKeys_ = [
|
||||
goog.events.listen(dragger, [
|
||||
goog.fx.Dragger.EventType.DRAG,
|
||||
goog.fx.Dragger.EventType.END
|
||||
], this.handleSliderChange_, undefined, this)
|
||||
];
|
||||
return dragger;
|
||||
};
|
||||
@@ -0,0 +1 @@
|
||||
@exportClass ol.control.ZoomToExtent ol.control.ZoomToExtentOptions
|
||||
@@ -0,0 +1,67 @@
|
||||
// FIXME works for View2D only
|
||||
|
||||
goog.provide('ol.control.ZoomToExtent');
|
||||
|
||||
goog.require('goog.dom');
|
||||
goog.require('goog.dom.TagName');
|
||||
goog.require('goog.events');
|
||||
goog.require('goog.events.EventType');
|
||||
goog.require('ol.control.Control');
|
||||
goog.require('ol.css');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Create a control that adds a button, which, when pressed, changes
|
||||
* the map view to a specific extent. To style this control use the
|
||||
* css selector .ol-zoom-extent.
|
||||
* @constructor
|
||||
* @extends {ol.control.Control}
|
||||
* @param {ol.control.ZoomToExtentOptions=} opt_options Options.
|
||||
*/
|
||||
ol.control.ZoomToExtent = function(opt_options) {
|
||||
var options = goog.isDef(opt_options) ? opt_options : {};
|
||||
|
||||
/**
|
||||
* @type {ol.Extent}
|
||||
* @private
|
||||
*/
|
||||
this.extent_ = goog.isDef(options.extent) ? options.extent : null;
|
||||
|
||||
var className = goog.isDef(options.className) ? options.className :
|
||||
'ol-zoom-extent';
|
||||
|
||||
var element = goog.dom.createDom(goog.dom.TagName.DIV, {
|
||||
'class': className + ' ' + ol.css.CLASS_UNSELECTABLE
|
||||
});
|
||||
var button = goog.dom.createDom(goog.dom.TagName.A, {
|
||||
'href': '#zoomExtent'
|
||||
});
|
||||
goog.dom.appendChild(element, button);
|
||||
|
||||
goog.events.listen(element, [
|
||||
goog.events.EventType.TOUCHEND,
|
||||
goog.events.EventType.CLICK
|
||||
], this.handleZoomToExtent_, false, this);
|
||||
|
||||
goog.base(this, {
|
||||
element: element,
|
||||
target: options.target
|
||||
});
|
||||
};
|
||||
goog.inherits(ol.control.ZoomToExtent, ol.control.Control);
|
||||
|
||||
|
||||
/**
|
||||
* @param {goog.events.BrowserEvent} browserEvent Browser event.
|
||||
* @private
|
||||
*/
|
||||
ol.control.ZoomToExtent.prototype.handleZoomToExtent_ = function(browserEvent) {
|
||||
// prevent #zoomExtent anchor from getting appended to the url
|
||||
browserEvent.preventDefault();
|
||||
var map = this.getMap();
|
||||
var view = map.getView().getView2D();
|
||||
var extent = goog.isNull(this.extent_) ?
|
||||
view.getProjection().getExtent() : this.extent_;
|
||||
view.fitExtent(extent, map.getSize());
|
||||
};
|
||||
@@ -0,0 +1,4 @@
|
||||
@exportSymbol ol.coordinate.createStringXY
|
||||
@exportSymbol ol.coordinate.toStringHDMS
|
||||
@exportSymbol ol.coordinate.toStringXY
|
||||
@exportSymbol ol.coordinate.fromProjectedArray
|
||||
@@ -0,0 +1,212 @@
|
||||
goog.provide('ol.Coordinate');
|
||||
goog.provide('ol.CoordinateArray');
|
||||
goog.provide('ol.CoordinateFormatType');
|
||||
goog.provide('ol.coordinate');
|
||||
|
||||
goog.require('goog.math');
|
||||
|
||||
|
||||
/**
|
||||
* @typedef {function((ol.Coordinate|undefined)): string}
|
||||
*/
|
||||
ol.CoordinateFormatType;
|
||||
|
||||
|
||||
/**
|
||||
* An array representing a coordinate.
|
||||
* @typedef {Array.<number>} ol.Coordinate
|
||||
*/
|
||||
ol.Coordinate;
|
||||
|
||||
|
||||
/**
|
||||
* An array of coordinate arrays.
|
||||
* @typedef {Array.<ol.Coordinate>}
|
||||
*/
|
||||
ol.CoordinateArray;
|
||||
|
||||
|
||||
/**
|
||||
* @param {ol.Coordinate} coordinate Coordinate.
|
||||
* @param {ol.Coordinate} delta Delta.
|
||||
* @return {ol.Coordinate} Coordinate.
|
||||
*/
|
||||
ol.coordinate.add = function(coordinate, delta) {
|
||||
coordinate[0] += delta[0];
|
||||
coordinate[1] += delta[1];
|
||||
return coordinate;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {number=} opt_precision Precision.
|
||||
* @return {ol.CoordinateFormatType} Coordinate format.
|
||||
*/
|
||||
ol.coordinate.createStringXY = function(opt_precision) {
|
||||
return (
|
||||
/**
|
||||
* @param {ol.Coordinate|undefined} coordinate Coordinate.
|
||||
* @return {string} String XY.
|
||||
*/
|
||||
function(coordinate) {
|
||||
return ol.coordinate.toStringXY(coordinate, opt_precision);
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {number} degrees Degrees.
|
||||
* @param {string} hemispheres Hemispheres.
|
||||
* @return {string} String.
|
||||
*/
|
||||
ol.coordinate.degreesToStringHDMS_ = function(degrees, hemispheres) {
|
||||
var normalizedDegrees = goog.math.modulo(degrees + 180, 360) - 180;
|
||||
var x = Math.abs(Math.round(3600 * normalizedDegrees));
|
||||
return Math.floor(x / 3600) + '\u00b0 ' +
|
||||
Math.floor((x / 60) % 60) + '\u2032 ' +
|
||||
Math.floor(x % 60) + '\u2033 ' +
|
||||
hemispheres.charAt(normalizedDegrees < 0 ? 1 : 0);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {ol.Coordinate} coordinate1 First coordinate.
|
||||
* @param {ol.Coordinate} coordinate2 Second coordinate.
|
||||
* @return {boolean} Whether the passed coordinates are equal.
|
||||
*/
|
||||
ol.coordinate.equals = function(coordinate1, coordinate2) {
|
||||
var equals = true;
|
||||
for (var i = coordinate1.length - 1; i >= 0; --i) {
|
||||
if (coordinate1[i] != coordinate2[i]) {
|
||||
equals = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return equals;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {ol.Coordinate} coordinate Coordinate.
|
||||
* @param {number} angle Angle.
|
||||
* @return {ol.Coordinate} Coordinate.
|
||||
*/
|
||||
ol.coordinate.rotate = function(coordinate, angle) {
|
||||
var cosAngle = Math.cos(angle);
|
||||
var sinAngle = Math.sin(angle);
|
||||
var x = coordinate[0] * cosAngle - coordinate[1] * sinAngle;
|
||||
var y = coordinate[1] * cosAngle + coordinate[0] * sinAngle;
|
||||
coordinate[0] = x;
|
||||
coordinate[1] = y;
|
||||
return coordinate;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {ol.Coordinate} coordinate Coordinate.
|
||||
* @param {number} s Scale.
|
||||
* @return {ol.Coordinate} Coordinate.
|
||||
*/
|
||||
ol.coordinate.scale = function(coordinate, s) {
|
||||
coordinate[0] *= s;
|
||||
coordinate[1] *= s;
|
||||
return coordinate;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {ol.Coordinate} coord1 First coordinate.
|
||||
* @param {ol.Coordinate} coord2 Second coordinate.
|
||||
* @return {number} Squared distance between coord1 and coord2.
|
||||
*/
|
||||
ol.coordinate.squaredDistance = function(coord1, coord2) {
|
||||
var dx = coord1[0] - coord2[0];
|
||||
var dy = coord1[1] - coord2[1];
|
||||
return dx * dx + dy * dy;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {ol.Coordinate} coordinate The coordinate.
|
||||
* @param {Array.<ol.Coordinate>} segment The two coordinates of the segment.
|
||||
* @return {Array} An array compatible with ol.Coordinate, but with 4 vaules:
|
||||
* [0] x-coordinate of the point closest to the given point on the segment;
|
||||
* [1] y-coordinate of the point closest to the given point on the segment;
|
||||
* [2] squared distance between given point and segment;
|
||||
* [3] describes how far between the two segment points the given point is.
|
||||
*/
|
||||
ol.coordinate.closestOnSegment = function(coordinate, segment) {
|
||||
var x0 = coordinate[0];
|
||||
var y0 = coordinate[1];
|
||||
var start = segment[0];
|
||||
var end = segment[1];
|
||||
var x1 = start[0];
|
||||
var y1 = start[1];
|
||||
var x2 = end[0];
|
||||
var y2 = end[1];
|
||||
var dx = x2 - x1;
|
||||
var dy = y2 - y1;
|
||||
var along = (dx == 0 && dy == 0) ? 0 :
|
||||
((dx * (x0 - x1)) + (dy * (y0 - y1))) / ((dx * dx + dy * dy) || 0);
|
||||
var x, y;
|
||||
if (along <= 0) {
|
||||
x = x1;
|
||||
y = y1;
|
||||
} else if (along >= 1) {
|
||||
x = x2;
|
||||
y = y2;
|
||||
} else {
|
||||
x = x1 + along * dx;
|
||||
y = y1 + along * dy;
|
||||
}
|
||||
var xDist = x - x0;
|
||||
var yDist = y - y0;
|
||||
return [x, y, xDist * xDist + yDist * yDist, along];
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {ol.Coordinate|undefined} coordinate Coordinate.
|
||||
* @return {string} Hemisphere, degrees, minutes and seconds.
|
||||
*/
|
||||
ol.coordinate.toStringHDMS = function(coordinate) {
|
||||
if (goog.isDef(coordinate)) {
|
||||
return ol.coordinate.degreesToStringHDMS_(coordinate[1], 'NS') + ' ' +
|
||||
ol.coordinate.degreesToStringHDMS_(coordinate[0], 'EW');
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {ol.Coordinate|undefined} coordinate Coordinate.
|
||||
* @param {number=} opt_precision Precision.
|
||||
* @return {string} XY.
|
||||
*/
|
||||
ol.coordinate.toStringXY = function(coordinate, opt_precision) {
|
||||
if (goog.isDef(coordinate)) {
|
||||
var precision = opt_precision || 0;
|
||||
return coordinate[0].toFixed(precision) + ', ' +
|
||||
coordinate[1].toFixed(precision);
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Create an ol.Coordinate from an Array and take into account axis order.
|
||||
* @param {Array} array The array with coordinates.
|
||||
* @param {string} axis the axis info.
|
||||
* @return {ol.Coordinate} The coordinate created.
|
||||
*/
|
||||
ol.coordinate.fromProjectedArray = function(array, axis) {
|
||||
var firstAxis = axis.charAt(0);
|
||||
if (firstAxis === 'n' || firstAxis === 's') {
|
||||
return [array[1], array[0]];
|
||||
} else {
|
||||
return array;
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,17 @@
|
||||
goog.provide('ol.css');
|
||||
|
||||
|
||||
/**
|
||||
* The CSS class that we'll give the DOM elements to have them unselectable.
|
||||
*
|
||||
* @const {string}
|
||||
*/
|
||||
ol.css.CLASS_UNSELECTABLE = 'ol-unselectable';
|
||||
|
||||
|
||||
/**
|
||||
* The CSS class for unsupported feature.
|
||||
*
|
||||
* @const {string}
|
||||
*/
|
||||
ol.css.CLASS_UNSUPPORTED = 'ol-unsupported';
|
||||
@@ -0,0 +1,2 @@
|
||||
@exportClass ol.DeviceOrientation ol.DeviceOrientationOptions
|
||||
@exportSymbol ol.DeviceOrientation.SUPPORTED
|
||||
@@ -0,0 +1,240 @@
|
||||
goog.provide('ol.DeviceOrientation');
|
||||
goog.provide('ol.DeviceOrientation.SUPPORTED');
|
||||
goog.provide('ol.DeviceOrientationProperty');
|
||||
|
||||
goog.require('goog.events');
|
||||
goog.require('goog.math');
|
||||
goog.require('ol.Object');
|
||||
|
||||
|
||||
/**
|
||||
* @enum {string}
|
||||
*/
|
||||
ol.DeviceOrientationProperty = {
|
||||
ALPHA: 'alpha',
|
||||
BETA: 'beta',
|
||||
GAMMA: 'gamma',
|
||||
HEADING: 'heading',
|
||||
TRACKING: 'tracking'
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* The ol.DeviceOrientation class provides access to DeviceOrientation
|
||||
* information and events, see the [HTML 5 DeviceOrientation Specification](
|
||||
* http://dev.w3.org/geo/api/spec-source-orientation) for more details.
|
||||
*
|
||||
* Many new computers, and especially mobile phones
|
||||
* and tablets, provide hardware support for device orientation. Web
|
||||
* developers targetting mobile devices will be especially interested in this
|
||||
* class.
|
||||
*
|
||||
* Device orientation data are relative to a common starting point. For mobile
|
||||
* devices, the starting point is to lay your phone face up on a table with the
|
||||
* top of the phone pointing north. This represents the zero state. All
|
||||
* angles are then relative to this state. For computers, it is the same except
|
||||
* the screen is open at 90 degrees.
|
||||
*
|
||||
* Device orientation is reported as three angles - `alpha`, `beta`, and
|
||||
* `gamma` - relative to the starting position along the three planar axes X, Y
|
||||
* and Z. The X axis runs from the left edge to the right edge through the
|
||||
* middle of the device. Similarly, the Y axis runs from the bottom to the top
|
||||
* of the device through the middle. The Z axis runs from the back to the front
|
||||
* through the middle. In the starting position, the X axis points to the
|
||||
* right, the Y axis points away from you and the Z axis points straight up
|
||||
* from the device lying flat.
|
||||
*
|
||||
* The three angles representing the device orientation are relative to the
|
||||
* three axes. `alpha` indicates how much the device has been rotated around the
|
||||
* Z axis, which is commonly interpreted as the compass heading (see note
|
||||
* below). `beta` indicates how much the device has been rotated around the X
|
||||
* axis, or how much it is tilted from front to back. `gamma` indicates how
|
||||
* much the device has been rotated around the Y axis, or how much it is tilted
|
||||
* from left to right.
|
||||
*
|
||||
* For most browsers, the `alpha` value returns the compass heading so if the
|
||||
* device points north, it will be 0. With Safari on iOS, the 0 value of
|
||||
* `alpha` is calculated from when device orientation was first requested.
|
||||
* ol.DeviceOrientation provides the `heading` property which normalizes this
|
||||
* behavior across all browsers for you.
|
||||
*
|
||||
* It is important to note that the HTML 5 DeviceOrientation specification
|
||||
* indicates that `alpha`, `beta` and `gamma` are in degrees while the
|
||||
* equivalent properties in ol.DeviceOrientation are in radians for consistency
|
||||
* with all other uses of angles throughout OpenLayers.
|
||||
*
|
||||
* @see http://dev.w3.org/geo/api/spec-source-orientation
|
||||
*
|
||||
* @constructor
|
||||
* @extends {ol.Object}
|
||||
* @param {ol.DeviceOrientationOptions=} opt_options Options.
|
||||
*/
|
||||
ol.DeviceOrientation = function(opt_options) {
|
||||
|
||||
goog.base(this);
|
||||
|
||||
var options = goog.isDef(opt_options) ? opt_options : {};
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {goog.events.Key}
|
||||
*/
|
||||
this.listenerKey_ = null;
|
||||
|
||||
goog.events.listen(this,
|
||||
ol.Object.getChangeEventType(ol.DeviceOrientationProperty.TRACKING),
|
||||
this.handleTrackingChanged_, false, this);
|
||||
|
||||
this.setTracking(goog.isDef(options.tracking) ? options.tracking : false);
|
||||
|
||||
};
|
||||
goog.inherits(ol.DeviceOrientation, ol.Object);
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
ol.DeviceOrientation.prototype.disposeInternal = function() {
|
||||
this.setTracking(false);
|
||||
goog.base(this, 'disposeInternal');
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Indicates if DeviceOrientation is supported in the user's browser.
|
||||
* @const
|
||||
* @type {boolean}
|
||||
*/
|
||||
ol.DeviceOrientation.SUPPORTED = 'DeviceOrientationEvent' in window;
|
||||
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {goog.events.BrowserEvent} browserEvent Event.
|
||||
*/
|
||||
ol.DeviceOrientation.prototype.orientationChange_ = function(browserEvent) {
|
||||
var event = /** @type {DeviceOrientationEvent} */
|
||||
(browserEvent.getBrowserEvent());
|
||||
if (goog.isDefAndNotNull(event.alpha)) {
|
||||
var alpha = goog.math.toRadians(event.alpha);
|
||||
this.set(ol.DeviceOrientationProperty.ALPHA, alpha);
|
||||
// event.absolute is undefined in iOS.
|
||||
if (goog.isBoolean(event.absolute) && event.absolute) {
|
||||
this.set(ol.DeviceOrientationProperty.HEADING, alpha);
|
||||
} else if (goog.isDefAndNotNull(event.webkitCompassHeading) &&
|
||||
goog.isDefAndNotNull(event.webkitCompassAccuracy) &&
|
||||
event.webkitCompassAccuracy != -1) {
|
||||
var heading = goog.math.toRadians(event.webkitCompassHeading);
|
||||
this.set(ol.DeviceOrientationProperty.HEADING, heading);
|
||||
}
|
||||
}
|
||||
if (goog.isDefAndNotNull(event.beta)) {
|
||||
this.set(ol.DeviceOrientationProperty.BETA,
|
||||
goog.math.toRadians(event.beta));
|
||||
}
|
||||
if (goog.isDefAndNotNull(event.gamma)) {
|
||||
this.set(ol.DeviceOrientationProperty.GAMMA,
|
||||
goog.math.toRadians(event.gamma));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {number|undefined} The alpha value of the DeviceOrientation,
|
||||
* in radians.
|
||||
*/
|
||||
ol.DeviceOrientation.prototype.getAlpha = function() {
|
||||
return /** @type {number|undefined} */ (
|
||||
this.get(ol.DeviceOrientationProperty.ALPHA));
|
||||
};
|
||||
goog.exportProperty(
|
||||
ol.DeviceOrientation.prototype,
|
||||
'getAlpha',
|
||||
ol.DeviceOrientation.prototype.getAlpha);
|
||||
|
||||
|
||||
/**
|
||||
* @return {number|undefined} The beta value of the DeviceOrientation,
|
||||
* in radians.
|
||||
*/
|
||||
ol.DeviceOrientation.prototype.getBeta = function() {
|
||||
return /** @type {number|undefined} */ (
|
||||
this.get(ol.DeviceOrientationProperty.BETA));
|
||||
};
|
||||
goog.exportProperty(
|
||||
ol.DeviceOrientation.prototype,
|
||||
'getBeta',
|
||||
ol.DeviceOrientation.prototype.getBeta);
|
||||
|
||||
|
||||
/**
|
||||
* @return {number|undefined} The gamma value of the DeviceOrientation,
|
||||
* in radians.
|
||||
*/
|
||||
ol.DeviceOrientation.prototype.getGamma = function() {
|
||||
return /** @type {number|undefined} */ (
|
||||
this.get(ol.DeviceOrientationProperty.GAMMA));
|
||||
};
|
||||
goog.exportProperty(
|
||||
ol.DeviceOrientation.prototype,
|
||||
'getGamma',
|
||||
ol.DeviceOrientation.prototype.getGamma);
|
||||
|
||||
|
||||
/**
|
||||
* @return {number|undefined} The heading of the device relative to
|
||||
* north, in radians, normalizing for different browser behavior.
|
||||
*/
|
||||
ol.DeviceOrientation.prototype.getHeading = function() {
|
||||
return /** @type {number|undefined} */ (
|
||||
this.get(ol.DeviceOrientationProperty.HEADING));
|
||||
};
|
||||
goog.exportProperty(
|
||||
ol.DeviceOrientation.prototype,
|
||||
'getHeading',
|
||||
ol.DeviceOrientation.prototype.getHeading);
|
||||
|
||||
|
||||
/**
|
||||
* Are we tracking the device's orientation?
|
||||
* @return {boolean} The current tracking state, true if tracking is on.
|
||||
*/
|
||||
ol.DeviceOrientation.prototype.getTracking = function() {
|
||||
return /** @type {boolean} */ (
|
||||
this.get(ol.DeviceOrientationProperty.TRACKING));
|
||||
};
|
||||
goog.exportProperty(
|
||||
ol.DeviceOrientation.prototype,
|
||||
'getTracking',
|
||||
ol.DeviceOrientation.prototype.getTracking);
|
||||
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
ol.DeviceOrientation.prototype.handleTrackingChanged_ = function() {
|
||||
if (ol.DeviceOrientation.SUPPORTED) {
|
||||
var tracking = this.getTracking();
|
||||
if (tracking && goog.isNull(this.listenerKey_)) {
|
||||
this.listenerKey_ = goog.events.listen(window, 'deviceorientation',
|
||||
this.orientationChange_, false, this);
|
||||
} else if (!tracking && !goog.isNull(this.listenerKey_)) {
|
||||
goog.events.unlistenByKey(this.listenerKey_);
|
||||
this.listenerKey_ = null;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Enable or disable tracking of DeviceOrientation events.
|
||||
* @param {boolean} tracking True to enable and false to disable tracking.
|
||||
*/
|
||||
ol.DeviceOrientation.prototype.setTracking = function(tracking) {
|
||||
this.set(ol.DeviceOrientationProperty.TRACKING, tracking);
|
||||
};
|
||||
goog.exportProperty(
|
||||
ol.DeviceOrientation.prototype,
|
||||
'setTracking',
|
||||
ol.DeviceOrientation.prototype.setTracking);
|
||||
@@ -0,0 +1,82 @@
|
||||
// FIXME add tests for browser features (Modernizr?)
|
||||
|
||||
goog.provide('ol.dom');
|
||||
goog.provide('ol.dom.BrowserFeature');
|
||||
|
||||
goog.require('goog.asserts');
|
||||
goog.require('goog.vec.Mat4');
|
||||
|
||||
|
||||
/**
|
||||
* @enum {boolean}
|
||||
*/
|
||||
ol.dom.BrowserFeature = {
|
||||
CAN_USE_CSS_TRANSFORM: false,
|
||||
CAN_USE_CSS_TRANSFORM3D: true
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {Element} element Element.
|
||||
* @param {string} value Value.
|
||||
*/
|
||||
ol.dom.setTransform = function(element, value) {
|
||||
var style = element.style;
|
||||
style.WebkitTransform = value;
|
||||
style.MozTransform = value;
|
||||
style.OTransform = value;
|
||||
style.transform = value;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {Element} element Element.
|
||||
* @param {goog.vec.Mat4.AnyType} transform Matrix.
|
||||
* @param {number=} opt_precision Precision.
|
||||
*/
|
||||
ol.dom.transformElement2D = function(element, transform, opt_precision) {
|
||||
// using matrix() causes gaps in Chrome and Firefox on Mac OS X, so prefer
|
||||
// matrix3d()
|
||||
var i;
|
||||
if (ol.dom.BrowserFeature.CAN_USE_CSS_TRANSFORM3D) {
|
||||
var value3D;
|
||||
if (goog.isDef(opt_precision)) {
|
||||
/** @type {Array.<string>} */
|
||||
var strings3D = new Array(16);
|
||||
for (i = 0; i < 16; ++i) {
|
||||
strings3D[i] = transform[i].toFixed(opt_precision);
|
||||
}
|
||||
value3D = strings3D.join(',');
|
||||
} else {
|
||||
value3D = transform.join(',');
|
||||
}
|
||||
ol.dom.setTransform(element, 'matrix3d(' + value3D + ')');
|
||||
} else if (ol.dom.BrowserFeature.CAN_USE_CSS_TRANSFORM) {
|
||||
/** @type {Array.<number>} */
|
||||
var transform2D = [
|
||||
goog.vec.Mat4.getElement(transform, 0, 0),
|
||||
goog.vec.Mat4.getElement(transform, 1, 0),
|
||||
goog.vec.Mat4.getElement(transform, 0, 1),
|
||||
goog.vec.Mat4.getElement(transform, 1, 1),
|
||||
goog.vec.Mat4.getElement(transform, 0, 3),
|
||||
goog.vec.Mat4.getElement(transform, 1, 3)
|
||||
];
|
||||
var value2D;
|
||||
if (goog.isDef(opt_precision)) {
|
||||
/** @type {Array.<string>} */
|
||||
var strings2D = new Array(6);
|
||||
for (i = 0; i < 6; ++i) {
|
||||
strings2D[i] = transform2D[i].toFixed(opt_precision);
|
||||
}
|
||||
value2D = strings2D.join(',');
|
||||
} else {
|
||||
value2D = transform2D.join(',');
|
||||
}
|
||||
ol.dom.setTransform(element, 'matrix(' + value2D + ')');
|
||||
} else {
|
||||
// FIXME check this code!
|
||||
var style = element.style;
|
||||
style.left = Math.round(goog.vec.Mat4.getElement(transform, 0, 3)) + 'px';
|
||||
style.top = Math.round(goog.vec.Mat4.getElement(transform, 1, 3)) + 'px';
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1 @@
|
||||
@exportSymbol ol.dom.Input
|
||||
@@ -0,0 +1,171 @@
|
||||
goog.provide('ol.dom.Input');
|
||||
goog.provide('ol.dom.InputProperty');
|
||||
|
||||
goog.require('goog.events');
|
||||
goog.require('goog.events.EventType');
|
||||
goog.require('ol.Object');
|
||||
|
||||
|
||||
/**
|
||||
* @enum {string}
|
||||
*/
|
||||
ol.dom.InputProperty = {
|
||||
VALUE: 'value',
|
||||
VALUE_AS_NUMBER: 'valueAsNumber',
|
||||
CHECKED: 'checked'
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Helper class for binding HTML input to an ol.Object
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* // bind a checkbox with id 'visible' to a layer's visibility
|
||||
* var visible = new ol.dom.Input(document.getElementById('visible'));
|
||||
* visible.bindTo('checked', layer, 'visible');
|
||||
*
|
||||
* @constructor
|
||||
* @extends {ol.Object}
|
||||
* @param {Element} target Target element.
|
||||
*/
|
||||
ol.dom.Input = function(target) {
|
||||
goog.base(this);
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {Element}
|
||||
*/
|
||||
this.target_ = target;
|
||||
|
||||
goog.events.listen(this.target_, goog.events.EventType.CHANGE,
|
||||
this.handleInputChanged_, false, this);
|
||||
|
||||
goog.events.listen(this,
|
||||
ol.Object.getChangeEventType(ol.dom.InputProperty.VALUE),
|
||||
this.handleValueChanged_, false, this);
|
||||
goog.events.listen(this,
|
||||
ol.Object.getChangeEventType(ol.dom.InputProperty.VALUE_AS_NUMBER),
|
||||
this.handleValueAsNumberChanged_, false, this);
|
||||
goog.events.listen(this,
|
||||
ol.Object.getChangeEventType(ol.dom.InputProperty.CHECKED),
|
||||
this.handleCheckedChanged_, false, this);
|
||||
};
|
||||
goog.inherits(ol.dom.Input, ol.Object);
|
||||
|
||||
|
||||
/**
|
||||
* If the input is a checkbox, return whether or not the checbox is checked.
|
||||
* @return {boolean|undefined} checked.
|
||||
*/
|
||||
ol.dom.Input.prototype.getChecked = function() {
|
||||
return /** @type {boolean} */ (this.get(ol.dom.InputProperty.CHECKED));
|
||||
};
|
||||
goog.exportProperty(
|
||||
ol.dom.Input.prototype,
|
||||
'getChecked',
|
||||
ol.dom.Input.prototype.getChecked);
|
||||
|
||||
|
||||
/**
|
||||
* Get the value of the input.
|
||||
* @return {string|undefined} input value.
|
||||
*/
|
||||
ol.dom.Input.prototype.getValue = function() {
|
||||
return /** @type {string} */ (this.get(ol.dom.InputProperty.VALUE));
|
||||
};
|
||||
goog.exportProperty(
|
||||
ol.dom.Input.prototype,
|
||||
'getValue',
|
||||
ol.dom.Input.prototype.getValue);
|
||||
|
||||
|
||||
/**
|
||||
* Get the value of the input as a number.
|
||||
* @return {number|null|undefined} input value as number.
|
||||
*/
|
||||
ol.dom.Input.prototype.getValueAsNumber = function() {
|
||||
return /** @type {number} */ (this.get(ol.dom.InputProperty.VALUE_AS_NUMBER));
|
||||
};
|
||||
goog.exportProperty(
|
||||
ol.dom.Input.prototype,
|
||||
'getValueAsNumber',
|
||||
ol.dom.Input.prototype.getValueAsNumber);
|
||||
|
||||
|
||||
/**
|
||||
* Sets the value of the input.
|
||||
* @param {string} value Value.
|
||||
*/
|
||||
ol.dom.Input.prototype.setValue = function(value) {
|
||||
this.set(ol.dom.InputProperty.VALUE, value);
|
||||
};
|
||||
goog.exportProperty(
|
||||
ol.dom.Input.prototype,
|
||||
'setValue',
|
||||
ol.dom.Input.prototype.setValue);
|
||||
|
||||
|
||||
/**
|
||||
* Sets the number value of the input.
|
||||
* @param {number} value Number value.
|
||||
*/
|
||||
ol.dom.Input.prototype.setValueAsNumber = function(value) {
|
||||
this.set(ol.dom.InputProperty.VALUE_AS_NUMBER, value);
|
||||
};
|
||||
goog.exportProperty(
|
||||
ol.dom.Input.prototype,
|
||||
'setValueAsNumber',
|
||||
ol.dom.Input.prototype.setValueAsNumber);
|
||||
|
||||
|
||||
/**
|
||||
* Set whether or not a checkbox is checked.
|
||||
* @param {boolean} checked Checked.
|
||||
*/
|
||||
ol.dom.Input.prototype.setChecked = function(checked) {
|
||||
this.set(ol.dom.InputProperty.CHECKED, checked);
|
||||
};
|
||||
goog.exportProperty(
|
||||
ol.dom.Input.prototype,
|
||||
'setChecked',
|
||||
ol.dom.Input.prototype.setChecked);
|
||||
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
ol.dom.Input.prototype.handleInputChanged_ = function() {
|
||||
if (this.target_.type === 'checkbox' || this.target_.type === 'radio') {
|
||||
this.setChecked(this.target_.checked);
|
||||
} else {
|
||||
this.setValue(this.target_.value);
|
||||
this.setValueAsNumber(this.target_.valueAsNumber);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
ol.dom.Input.prototype.handleCheckedChanged_ = function() {
|
||||
this.target_.checked = this.getChecked() ? 'checked' : undefined;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
ol.dom.Input.prototype.handleValueChanged_ = function() {
|
||||
this.target_.value = this.getValue();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
ol.dom.Input.prototype.handleValueAsNumberChanged_ = function() {
|
||||
// firefox raises an exception if this.target_.valueAsNumber is set instead
|
||||
this.target_.value = this.getValueAsNumber();
|
||||
};
|
||||
@@ -0,0 +1,7 @@
|
||||
@exportSymbol ol.easing.bounce
|
||||
@exportSymbol ol.easing.easeIn
|
||||
@exportSymbol ol.easing.easeOut
|
||||
@exportSymbol ol.easing.elastic
|
||||
@exportSymbol ol.easing.inAndOut
|
||||
@exportSymbol ol.easing.linear
|
||||
@exportSymbol ol.easing.upAndDown
|
||||
@@ -0,0 +1,83 @@
|
||||
goog.provide('ol.easing');
|
||||
|
||||
goog.require('goog.fx.easing');
|
||||
|
||||
|
||||
/**
|
||||
* from https://raw.github.com/DmitryBaranovskiy/raphael/master/raphael.js
|
||||
* @param {number} t Input between 0 and 1.
|
||||
* @return {number} Output between 0 and 1.
|
||||
*/
|
||||
ol.easing.bounce = function(t) {
|
||||
var s = 7.5625, p = 2.75, l;
|
||||
if (t < (1 / p)) {
|
||||
l = s * t * t;
|
||||
} else {
|
||||
if (t < (2 / p)) {
|
||||
t -= (1.5 / p);
|
||||
l = s * t * t + 0.75;
|
||||
} else {
|
||||
if (t < (2.5 / p)) {
|
||||
t -= (2.25 / p);
|
||||
l = s * t * t + 0.9375;
|
||||
} else {
|
||||
t -= (2.625 / p);
|
||||
l = s * t * t + 0.984375;
|
||||
}
|
||||
}
|
||||
}
|
||||
return l;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {number} t Input between 0 and 1.
|
||||
* @return {number} Output between 0 and 1.
|
||||
*/
|
||||
ol.easing.easeIn = goog.fx.easing.easeIn;
|
||||
|
||||
|
||||
/**
|
||||
* @param {number} t Input between 0 and 1.
|
||||
* @return {number} Output between 0 and 1.
|
||||
*/
|
||||
ol.easing.easeOut = goog.fx.easing.easeOut;
|
||||
|
||||
|
||||
/**
|
||||
* from https://raw.github.com/DmitryBaranovskiy/raphael/master/raphael.js
|
||||
* @param {number} t Input between 0 and 1.
|
||||
* @return {number} Output between 0 and 1.
|
||||
*/
|
||||
ol.easing.elastic = function(t) {
|
||||
return Math.pow(2, -10 * t) * Math.sin((t - 0.075) * (2 * Math.PI) / 0.3) + 1;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {number} t Input between 0 and 1.
|
||||
* @return {number} Output between 0 and 1.
|
||||
*/
|
||||
ol.easing.inAndOut = goog.fx.easing.inAndOut;
|
||||
|
||||
|
||||
/**
|
||||
* @param {number} t Input between 0 and 1.
|
||||
* @return {number} Output between 0 and 1.
|
||||
*/
|
||||
ol.easing.linear = function(t) {
|
||||
return t;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {number} t Input between 0 and 1.
|
||||
* @return {number} Output between 0 and 1.
|
||||
*/
|
||||
ol.easing.upAndDown = function(t) {
|
||||
if (t < 0.5) {
|
||||
return ol.easing.inAndOut(2 * t);
|
||||
} else {
|
||||
return 1 - ol.easing.inAndOut(2 * (t - 0.5));
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,10 @@
|
||||
goog.provide('ol.ellipsoid.BESSEL1841');
|
||||
|
||||
goog.require('ol.Ellipsoid');
|
||||
|
||||
|
||||
/**
|
||||
* @const
|
||||
* @type {ol.Ellipsoid}
|
||||
*/
|
||||
ol.ellipsoid.BESSEL1841 = new ol.Ellipsoid(6377397.155, 1 / 299.15281285);
|
||||
@@ -0,0 +1,185 @@
|
||||
goog.provide('ol.Ellipsoid');
|
||||
|
||||
goog.require('goog.math');
|
||||
goog.require('ol.Coordinate');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
* @param {number} a Major radius.
|
||||
* @param {number} flattening Flattening.
|
||||
*/
|
||||
ol.Ellipsoid = function(a, flattening) {
|
||||
|
||||
/**
|
||||
* @const
|
||||
* @type {number}
|
||||
*/
|
||||
this.a = a;
|
||||
|
||||
/**
|
||||
* @const
|
||||
* @type {number}
|
||||
*/
|
||||
this.flattening = flattening;
|
||||
|
||||
/**
|
||||
* @const
|
||||
* @type {number}
|
||||
*/
|
||||
this.b = this.a * (1 - this.flattening);
|
||||
|
||||
/**
|
||||
* @const
|
||||
* @type {number}
|
||||
*/
|
||||
this.eSquared = 2 * flattening - flattening * flattening;
|
||||
|
||||
/**
|
||||
* @const
|
||||
* @type {number}
|
||||
*/
|
||||
this.e = Math.sqrt(this.eSquared);
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {ol.Coordinate} c1 Coordinate 1.
|
||||
* @param {ol.Coordinate} c2 Coordinate 1.
|
||||
* @param {number=} opt_minDeltaLambda Minimum delta lambda for convergence.
|
||||
* @param {number=} opt_maxIterations Maximum iterations.
|
||||
* @return {{distance: number, initialBearing: number, finalBearing: number}}
|
||||
* Vincenty.
|
||||
*/
|
||||
ol.Ellipsoid.prototype.vincenty =
|
||||
function(c1, c2, opt_minDeltaLambda, opt_maxIterations) {
|
||||
var minDeltaLambda = goog.isDef(opt_minDeltaLambda) ?
|
||||
opt_minDeltaLambda : 1e-12;
|
||||
var maxIterations = goog.isDef(opt_maxIterations) ?
|
||||
opt_maxIterations : 100;
|
||||
var f = this.flattening;
|
||||
var lat1 = goog.math.toRadians(c1[1]);
|
||||
var lat2 = goog.math.toRadians(c2[1]);
|
||||
var deltaLon = goog.math.toRadians(c2[0] - c1[0]);
|
||||
var U1 = Math.atan((1 - f) * Math.tan(lat1));
|
||||
var cosU1 = Math.cos(U1);
|
||||
var sinU1 = Math.sin(U1);
|
||||
var U2 = Math.atan((1 - f) * Math.tan(lat2));
|
||||
var cosU2 = Math.cos(U2);
|
||||
var sinU2 = Math.sin(U2);
|
||||
var lambda = deltaLon;
|
||||
var cosSquaredAlpha, sinAlpha;
|
||||
var cosLambda, deltaLambda = Infinity, sinLambda;
|
||||
var cos2SigmaM, cosSigma, sigma, sinSigma;
|
||||
var i;
|
||||
for (i = maxIterations; i > 0; --i) {
|
||||
cosLambda = Math.cos(lambda);
|
||||
sinLambda = Math.sin(lambda);
|
||||
var x = cosU2 * sinLambda;
|
||||
var y = cosU1 * sinU2 - sinU1 * cosU2 * cosLambda;
|
||||
sinSigma = Math.sqrt(x * x + y * y);
|
||||
if (sinSigma === 0) {
|
||||
return {
|
||||
distance: 0,
|
||||
initialBearing: 0,
|
||||
finalBearing: 0
|
||||
};
|
||||
}
|
||||
cosSigma = sinU1 * sinU2 + cosU1 * cosU2 * cosLambda;
|
||||
sigma = Math.atan2(sinSigma, cosSigma);
|
||||
sinAlpha = cosU1 * cosU2 * sinLambda / sinSigma;
|
||||
cosSquaredAlpha = 1 - sinAlpha * sinAlpha;
|
||||
cos2SigmaM = cosSigma - 2 * sinU1 * sinU2 / cosSquaredAlpha;
|
||||
if (isNaN(cos2SigmaM)) {
|
||||
cos2SigmaM = 0;
|
||||
}
|
||||
var C = f / 16 * cosSquaredAlpha * (4 + f * (4 - 3 * cosSquaredAlpha));
|
||||
var lambdaPrime = deltaLon + (1 - C) * f * sinAlpha * (sigma +
|
||||
C * sinSigma * (cos2SigmaM +
|
||||
C * cosSigma * (2 * cos2SigmaM * cos2SigmaM - 1)));
|
||||
deltaLambda = Math.abs(lambdaPrime - lambda);
|
||||
lambda = lambdaPrime;
|
||||
if (deltaLambda < minDeltaLambda) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i === 0) {
|
||||
return {
|
||||
distance: NaN,
|
||||
finalBearing: NaN,
|
||||
initialBearing: NaN
|
||||
};
|
||||
}
|
||||
var aSquared = this.a * this.a;
|
||||
var bSquared = this.b * this.b;
|
||||
var uSquared = cosSquaredAlpha * (aSquared - bSquared) / bSquared;
|
||||
var A = 1 + uSquared / 16384 *
|
||||
(4096 + uSquared * (uSquared * (320 - 175 * uSquared) - 768));
|
||||
var B = uSquared / 1024 *
|
||||
(256 + uSquared * (uSquared * (74 - 47 * uSquared) - 128));
|
||||
var deltaSigma = B * sinSigma * (cos2SigmaM + B / 4 *
|
||||
(cosSigma * (2 * cos2SigmaM * cos2SigmaM - 1) -
|
||||
B / 6 * cos2SigmaM * (4 * sinSigma * sinSigma - 3) *
|
||||
(4 * cos2SigmaM * cos2SigmaM - 3)));
|
||||
cosLambda = Math.cos(lambda);
|
||||
sinLambda = Math.sin(lambda);
|
||||
var alpha1 = Math.atan2(cosU2 * sinLambda,
|
||||
cosU1 * sinU2 - sinU1 * cosU2 * cosLambda);
|
||||
var alpha2 = Math.atan2(cosU1 * sinLambda,
|
||||
cosU1 * sinU2 * cosLambda - sinU1 * cosU2);
|
||||
return {
|
||||
distance: this.b * A * (sigma - deltaSigma),
|
||||
initialBearing: goog.math.toDegrees(alpha1),
|
||||
finalBearing: goog.math.toDegrees(alpha2)
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns the distance from c1 to c2 using Vincenty.
|
||||
*
|
||||
* @param {ol.Coordinate} c1 Coordinate 1.
|
||||
* @param {ol.Coordinate} c2 Coordinate 1.
|
||||
* @param {number=} opt_minDeltaLambda Minimum delta lambda for convergence.
|
||||
* @param {number=} opt_maxIterations Maximum iterations.
|
||||
* @return {number} Vincenty distance.
|
||||
*/
|
||||
ol.Ellipsoid.prototype.vincentyDistance =
|
||||
function(c1, c2, opt_minDeltaLambda, opt_maxIterations) {
|
||||
var vincenty = this.vincenty(c1, c2, opt_minDeltaLambda, opt_maxIterations);
|
||||
return vincenty.distance;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns the final bearing from c1 to c2 using Vincenty.
|
||||
*
|
||||
* @param {ol.Coordinate} c1 Coordinate 1.
|
||||
* @param {ol.Coordinate} c2 Coordinate 1.
|
||||
* @param {number=} opt_minDeltaLambda Minimum delta lambda for convergence.
|
||||
* @param {number=} opt_maxIterations Maximum iterations.
|
||||
* @return {number} Initial bearing.
|
||||
*/
|
||||
ol.Ellipsoid.prototype.vincentyFinalBearing =
|
||||
function(c1, c2, opt_minDeltaLambda, opt_maxIterations) {
|
||||
var vincenty = this.vincenty(c1, c2, opt_minDeltaLambda, opt_maxIterations);
|
||||
return vincenty.finalBearing;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns the initial bearing from c1 to c2 using Vincenty.
|
||||
*
|
||||
* @param {ol.Coordinate} c1 Coordinate 1.
|
||||
* @param {ol.Coordinate} c2 Coordinate 1.
|
||||
* @param {number=} opt_minDeltaLambda Minimum delta lambda for convergence.
|
||||
* @param {number=} opt_maxIterations Maximum iterations.
|
||||
* @return {number} Initial bearing.
|
||||
*/
|
||||
ol.Ellipsoid.prototype.vincentyInitialBearing =
|
||||
function(c1, c2, opt_minDeltaLambda, opt_maxIterations) {
|
||||
var vincenty = this.vincenty(c1, c2, opt_minDeltaLambda, opt_maxIterations);
|
||||
return vincenty.initialBearing;
|
||||
};
|
||||
@@ -0,0 +1,10 @@
|
||||
goog.provide('ol.ellipsoid.WGS84');
|
||||
|
||||
goog.require('ol.Ellipsoid');
|
||||
|
||||
|
||||
/**
|
||||
* @const
|
||||
* @type {ol.Ellipsoid}
|
||||
*/
|
||||
ol.ellipsoid.WGS84 = new ol.Ellipsoid(6378137, 1 / 298.257223563);
|
||||
@@ -0,0 +1,2 @@
|
||||
@exportSymbol ol.expr.parse
|
||||
@exportSymbol ol.expr.register
|
||||
@@ -0,0 +1,3 @@
|
||||
/**
|
||||
* @namespace ol.expr
|
||||
*/
|
||||
@@ -0,0 +1,292 @@
|
||||
goog.provide('ol.expr');
|
||||
goog.provide('ol.expr.functions');
|
||||
|
||||
goog.require('ol.Extent');
|
||||
goog.require('ol.Feature');
|
||||
goog.require('ol.expr.Call');
|
||||
goog.require('ol.expr.Expression');
|
||||
goog.require('ol.expr.Identifier');
|
||||
goog.require('ol.expr.Parser');
|
||||
goog.require('ol.extent');
|
||||
goog.require('ol.geom.GeometryType');
|
||||
|
||||
|
||||
/**
|
||||
* Evaluate an expression with a feature. The feature attributes will be used
|
||||
* as the evaluation scope. The `ol.expr.lib` functions will be used as
|
||||
* function scope. The feature itself will be used as the `this` argument.
|
||||
*
|
||||
* @param {ol.expr.Expression} expr The expression.
|
||||
* @param {ol.Feature=} opt_feature The feature.
|
||||
* @return {*} The result of the expression.
|
||||
*/
|
||||
ol.expr.evaluateFeature = function(expr, opt_feature) {
|
||||
var result;
|
||||
if (goog.isDef(opt_feature)) {
|
||||
result = expr.evaluate(
|
||||
opt_feature.getAttributes(), ol.expr.lib, opt_feature);
|
||||
} else {
|
||||
result = expr.evaluate();
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Parse an expression.
|
||||
* @param {string} source The expression source (e.g. `'foo + 2'`).
|
||||
* @return {ol.expr.Expression} An expression instance that can be
|
||||
* evaluated within some scope to provide a value.
|
||||
*/
|
||||
ol.expr.parse = function(source) {
|
||||
var parser = new ol.expr.Parser();
|
||||
return parser.parse(source);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Register a library function to be used in expressions.
|
||||
* @param {string} name The function name (e.g. 'myFunc').
|
||||
* @param {function(this:ol.Feature)} func The function to be called in an
|
||||
* expression. This function will be called with a feature as the `this`
|
||||
* argument when the expression is evaluated in the context of a features.
|
||||
*/
|
||||
ol.expr.register = function(name, func) {
|
||||
ol.expr.lib[name] = func;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Determines whether an expression is a call expression that calls one of the
|
||||
* `ol.expr.lib` functions.
|
||||
*
|
||||
* @param {ol.expr.Expression} expr The candidate expression.
|
||||
* @return {string|undefined} If the candidate expression is a call to a lib
|
||||
* function, the return will be the function name. If not, the return will be
|
||||
* `undefined`.
|
||||
*/
|
||||
ol.expr.isLibCall = function(expr) {
|
||||
var name;
|
||||
if (expr instanceof ol.expr.Call) {
|
||||
var callee = expr.getCallee();
|
||||
if (callee instanceof ol.expr.Identifier) {
|
||||
name = callee.getName();
|
||||
if (!ol.expr.lib.hasOwnProperty(name)) {
|
||||
name = undefined;
|
||||
}
|
||||
}
|
||||
}
|
||||
return name;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Library of well-known functions. These are available to expressions parsed
|
||||
* with `ol.expr.parse`.
|
||||
*
|
||||
* @type {Object.<string, function(...)>}
|
||||
*/
|
||||
ol.expr.lib = {};
|
||||
|
||||
|
||||
/**
|
||||
* Enumeration of library function names.
|
||||
*
|
||||
* @enum {string}
|
||||
*/
|
||||
ol.expr.functions = {
|
||||
CONCAT: 'concat',
|
||||
EXTENT: 'extent',
|
||||
FID: 'fid',
|
||||
GEOMETRY_TYPE: 'geometryType',
|
||||
RENDER_INTENT: 'renderIntent',
|
||||
INTERSECTS: 'intersects',
|
||||
CONTAINS: 'contains',
|
||||
DWITHIN: 'dwithin',
|
||||
WITHIN: 'within',
|
||||
LIKE: 'like',
|
||||
IEQ: 'ieq',
|
||||
INEQ: 'ineq'
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Concatenate strings. All provided arguments will be cast to string and
|
||||
* concatenated.
|
||||
* @param {...string} var_args Strings to concatenate.
|
||||
* @return {string} All input arguments concatenated as strings.
|
||||
* @this {ol.Feature}
|
||||
*/
|
||||
ol.expr.lib[ol.expr.functions.CONCAT] = function(var_args) {
|
||||
var str = '';
|
||||
for (var i = 0, ii = arguments.length; i < ii; ++i) {
|
||||
str += String(arguments[i]);
|
||||
}
|
||||
return str;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Determine if a feature's extent intersects the provided extent.
|
||||
* @param {number} minX Minimum x-coordinate value.
|
||||
* @param {number} maxX Maximum x-coordinate value.
|
||||
* @param {number} minY Minimum y-coordinate value.
|
||||
* @param {number} maxY Maximum y-coordinate value.
|
||||
* @param {string=} opt_projection Projection of the extent.
|
||||
* @param {string=} opt_attribute Name of the geometry attribute to use.
|
||||
* @return {boolean} The provided extent intersects the feature's extent.
|
||||
* @this {ol.Feature}
|
||||
*/
|
||||
ol.expr.lib[ol.expr.functions.EXTENT] = function(minX, maxX, minY, maxY,
|
||||
opt_projection, opt_attribute) {
|
||||
var intersects = false;
|
||||
var geometry = goog.isDef(opt_attribute) ?
|
||||
this.get(opt_attribute) : this.getGeometry();
|
||||
if (geometry) {
|
||||
intersects = ol.extent.intersects(geometry.getBounds(),
|
||||
[minX, maxX, minY, maxY]);
|
||||
}
|
||||
return intersects;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Determine if the feature identifier matches any of the provided values.
|
||||
* @param {...string} var_args Feature identifiers.
|
||||
* @return {boolean} The feature's identifier matches one of the given values.
|
||||
* @this {ol.Feature}
|
||||
*/
|
||||
ol.expr.lib[ol.expr.functions.FID] = function(var_args) {
|
||||
var matches = false;
|
||||
var id = this.getFeatureId();
|
||||
if (goog.isDef(id)) {
|
||||
for (var i = 0, ii = arguments.length; i < ii; ++i) {
|
||||
if (arguments[i] === id) {
|
||||
matches = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return matches;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Determine if two strings are like one another, based on simple pattern
|
||||
* matching.
|
||||
* @param {string} value The string to test.
|
||||
* @param {string} pattern The comparison pattern.
|
||||
* @param {string} wildCard The wildcard character to use.
|
||||
* @param {string} singleChar The single character to use.
|
||||
* @param {string} escapeChar The escape character to use.
|
||||
* @param {boolean} matchCase Should we match case or not?
|
||||
* @this {ol.Feature}
|
||||
*/
|
||||
ol.expr.lib[ol.expr.functions.LIKE] = function(value, pattern, wildCard,
|
||||
singleChar, escapeChar, matchCase) {
|
||||
if (wildCard == '.') {
|
||||
throw new Error('"." is an unsupported wildCard character for ' +
|
||||
'the "like" function');
|
||||
}
|
||||
// set UMN MapServer defaults for unspecified parameters
|
||||
wildCard = goog.isDef(wildCard) ? wildCard : '*';
|
||||
singleChar = goog.isDef(singleChar) ? singleChar : '.';
|
||||
escapeChar = goog.isDef(escapeChar) ? escapeChar : '!';
|
||||
pattern = pattern.replace(
|
||||
new RegExp('\\' + escapeChar + '(.|$)', 'g'), '\\$1');
|
||||
pattern = pattern.replace(
|
||||
new RegExp('\\' + singleChar, 'g'), '.');
|
||||
pattern = pattern.replace(
|
||||
new RegExp('\\' + wildCard, 'g'), '.*');
|
||||
pattern = pattern.replace(
|
||||
new RegExp('\\\\.\\*', 'g'), '\\' + wildCard);
|
||||
pattern = pattern.replace(
|
||||
new RegExp('\\\\\\.', 'g'), '\\' + singleChar);
|
||||
var modifiers = (matchCase === false) ? 'gi' : 'g';
|
||||
return new RegExp(pattern, modifiers).test(value);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Case insensitive comparison for equality.
|
||||
* @param {*} first First value.
|
||||
* @param {*} second Second value.
|
||||
* @this {ol.Feature}
|
||||
*/
|
||||
ol.expr.lib[ol.expr.functions.IEQ] = function(first, second) {
|
||||
if (goog.isString(first) && goog.isString(second)) {
|
||||
return first.toUpperCase() == second.toUpperCase();
|
||||
} else {
|
||||
return first == second;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Case insensitive comparison for non-equality.
|
||||
* @param {*} first First value.
|
||||
* @param {*} second Second value.
|
||||
* @this {ol.Feature}
|
||||
*/
|
||||
ol.expr.lib[ol.expr.functions.INEQ] = function(first, second) {
|
||||
if (goog.isString(first) && goog.isString(second)) {
|
||||
return first.toUpperCase() != second.toUpperCase();
|
||||
} else {
|
||||
return first != second;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Determine if a feature's default geometry is of the given type.
|
||||
* @param {ol.geom.GeometryType} type Geometry type.
|
||||
* @return {boolean} The feature's default geometry is of the given type.
|
||||
* @this {ol.Feature}
|
||||
*/
|
||||
ol.expr.lib[ol.expr.functions.GEOMETRY_TYPE] = function(type) {
|
||||
var same = false;
|
||||
var geometry = this.getGeometry();
|
||||
if (geometry) {
|
||||
same = geometry.getType() === type;
|
||||
}
|
||||
return same;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Determine if a feature's renderIntent matches the given one.
|
||||
* @param {string} renderIntent Render intent.
|
||||
* @return {boolean} The feature's renderIntent matches the given one.
|
||||
* @this {ol.Feature}
|
||||
*/
|
||||
ol.expr.lib[ol.expr.functions.RENDER_INTENT] = function(renderIntent) {
|
||||
return this.renderIntent == renderIntent;
|
||||
};
|
||||
|
||||
|
||||
ol.expr.lib[ol.expr.functions.INTERSECTS] = function(geom, opt_projection,
|
||||
opt_attribute) {
|
||||
throw new Error('Spatial function not implemented: ' +
|
||||
ol.expr.functions.INTERSECTS);
|
||||
};
|
||||
|
||||
|
||||
ol.expr.lib[ol.expr.functions.WITHIN] = function(geom, opt_projection,
|
||||
opt_attribute) {
|
||||
throw new Error('Spatial function not implemented: ' +
|
||||
ol.expr.functions.WITHIN);
|
||||
};
|
||||
|
||||
|
||||
ol.expr.lib[ol.expr.functions.CONTAINS] = function(geom, opt_projeciton,
|
||||
opt_attribute) {
|
||||
throw new Error('Spatial function not implemented: ' +
|
||||
ol.expr.functions.CONTAINS);
|
||||
};
|
||||
|
||||
|
||||
ol.expr.lib[ol.expr.functions.DWITHIN] = function(geom, distance, units,
|
||||
opt_projection, opt_attribute) {
|
||||
throw new Error('Spatial function not implemented: ' +
|
||||
ol.expr.functions.DWITHIN);
|
||||
};
|
||||
@@ -0,0 +1,626 @@
|
||||
goog.provide('ol.expr.Call');
|
||||
goog.provide('ol.expr.Comparison');
|
||||
goog.provide('ol.expr.ComparisonOp');
|
||||
goog.provide('ol.expr.Expression');
|
||||
goog.provide('ol.expr.Identifier');
|
||||
goog.provide('ol.expr.Literal');
|
||||
goog.provide('ol.expr.Logical');
|
||||
goog.provide('ol.expr.LogicalOp');
|
||||
goog.provide('ol.expr.Math');
|
||||
goog.provide('ol.expr.MathOp');
|
||||
goog.provide('ol.expr.Member');
|
||||
goog.provide('ol.expr.Not');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Base class for all expressions. Instances of ol.expr.Expression
|
||||
* correspond to a limited set of ECMAScript 5.1 expressions.
|
||||
* http://www.ecma-international.org/ecma-262/5.1/#sec-11
|
||||
*
|
||||
* This base class should not be constructed directly. Instead, use one of
|
||||
* the subclass constructors.
|
||||
*
|
||||
* @constructor
|
||||
*/
|
||||
ol.expr.Expression = function() {};
|
||||
|
||||
|
||||
/**
|
||||
* Evaluate the expression and return the result.
|
||||
*
|
||||
* @param {Object=} opt_scope Evaluation scope. All properties of this object
|
||||
* will be available as variables when evaluating the expression. If not
|
||||
* provided, `null` will be used.
|
||||
* @param {Object=} opt_fns Optional scope for looking up functions. If not
|
||||
* provided, functions will be looked in the evaluation scope.
|
||||
* @param {Object=} opt_this Object to use as this when evaluating call
|
||||
* expressions. If not provided, `this` will resolve to a new object.
|
||||
* @return {*} Result of the expression.
|
||||
*/
|
||||
ol.expr.Expression.prototype.evaluate = goog.abstractMethod;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* A call expression (e.g. `foo(bar)`).
|
||||
*
|
||||
* @constructor
|
||||
* @extends {ol.expr.Expression}
|
||||
* @param {ol.expr.Expression} callee An expression that resolves to a
|
||||
* function.
|
||||
* @param {Array.<ol.expr.Expression>} args Arguments.
|
||||
*/
|
||||
ol.expr.Call = function(callee, args) {
|
||||
|
||||
/**
|
||||
* @type {ol.expr.Expression}
|
||||
* @private
|
||||
*/
|
||||
this.callee_ = callee;
|
||||
|
||||
/**
|
||||
* @type {Array.<ol.expr.Expression>}
|
||||
* @private
|
||||
*/
|
||||
this.args_ = args;
|
||||
|
||||
};
|
||||
goog.inherits(ol.expr.Call, ol.expr.Expression);
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
ol.expr.Call.prototype.evaluate = function(opt_scope, opt_fns, opt_this) {
|
||||
var fnScope = goog.isDefAndNotNull(opt_fns) ? opt_fns : opt_scope;
|
||||
var fn = this.callee_.evaluate(fnScope);
|
||||
if (!fn || !goog.isFunction(fn)) {
|
||||
throw new Error('Expected function but found ' + fn);
|
||||
}
|
||||
var thisArg = goog.isDef(opt_this) ? opt_this : {};
|
||||
|
||||
var len = this.args_.length;
|
||||
var values = new Array(len);
|
||||
for (var i = 0; i < len; ++i) {
|
||||
values[i] = this.args_[i].evaluate(opt_scope, opt_fns, opt_this);
|
||||
}
|
||||
return fn.apply(thisArg, values);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get the argument list.
|
||||
* @return {Array.<ol.expr.Expression>} The argument.
|
||||
*/
|
||||
ol.expr.Call.prototype.getArgs = function() {
|
||||
return this.args_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get the callee expression.
|
||||
* @return {ol.expr.Expression} The callee expression.
|
||||
*/
|
||||
ol.expr.Call.prototype.getCallee = function() {
|
||||
return this.callee_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @enum {string}
|
||||
*/
|
||||
ol.expr.ComparisonOp = {
|
||||
EQ: '==',
|
||||
NEQ: '!=',
|
||||
STRICT_EQ: '===',
|
||||
STRICT_NEQ: '!==',
|
||||
GT: '>',
|
||||
LT: '<',
|
||||
GTE: '>=',
|
||||
LTE: '<='
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* A comparison expression (e.g. `foo >= 42`, `bar != "chicken"`).
|
||||
*
|
||||
* @constructor
|
||||
* @extends {ol.expr.Expression}
|
||||
* @param {ol.expr.ComparisonOp} operator Comparison operator.
|
||||
* @param {ol.expr.Expression} left Left expression.
|
||||
* @param {ol.expr.Expression} right Right expression.
|
||||
*/
|
||||
ol.expr.Comparison = function(operator, left, right) {
|
||||
|
||||
/**
|
||||
* @type {ol.expr.ComparisonOp}
|
||||
* @private
|
||||
*/
|
||||
this.operator_ = operator;
|
||||
|
||||
/**
|
||||
* @type {ol.expr.Expression}
|
||||
* @private
|
||||
*/
|
||||
this.left_ = left;
|
||||
|
||||
/**
|
||||
* @type {ol.expr.Expression}
|
||||
* @private
|
||||
*/
|
||||
this.right_ = right;
|
||||
|
||||
};
|
||||
goog.inherits(ol.expr.Comparison, ol.expr.Expression);
|
||||
|
||||
|
||||
/**
|
||||
* Determine if a given string is a valid comparison operator.
|
||||
* @param {string} candidate Operator to test.
|
||||
* @return {boolean} The operator is valid.
|
||||
*/
|
||||
ol.expr.Comparison.isValidOp = (function() {
|
||||
var valid = {};
|
||||
for (var key in ol.expr.ComparisonOp) {
|
||||
valid[ol.expr.ComparisonOp[key]] = true;
|
||||
}
|
||||
return function isValidOp(candidate) {
|
||||
return !!valid[candidate];
|
||||
};
|
||||
}());
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
ol.expr.Comparison.prototype.evaluate = function(opt_scope, opt_fns, opt_this) {
|
||||
var result;
|
||||
var rightVal = this.right_.evaluate(opt_scope, opt_fns, opt_this);
|
||||
var leftVal = this.left_.evaluate(opt_scope, opt_fns, opt_this);
|
||||
|
||||
var op = this.operator_;
|
||||
if (op === ol.expr.ComparisonOp.EQ) {
|
||||
result = leftVal == rightVal;
|
||||
} else if (op === ol.expr.ComparisonOp.NEQ) {
|
||||
result = leftVal != rightVal;
|
||||
} else if (op === ol.expr.ComparisonOp.STRICT_EQ) {
|
||||
result = leftVal === rightVal;
|
||||
} else if (op === ol.expr.ComparisonOp.STRICT_NEQ) {
|
||||
result = leftVal !== rightVal;
|
||||
} else if (op === ol.expr.ComparisonOp.GT) {
|
||||
result = leftVal > rightVal;
|
||||
} else if (op === ol.expr.ComparisonOp.LT) {
|
||||
result = leftVal < rightVal;
|
||||
} else if (op === ol.expr.ComparisonOp.GTE) {
|
||||
result = leftVal >= rightVal;
|
||||
} else if (op === ol.expr.ComparisonOp.LTE) {
|
||||
result = leftVal <= rightVal;
|
||||
} else {
|
||||
throw new Error('Unsupported comparison operator: ' + this.operator_);
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get the comparison operator.
|
||||
* @return {string} The comparison operator.
|
||||
*/
|
||||
ol.expr.Comparison.prototype.getOperator = function() {
|
||||
return this.operator_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get the left expression.
|
||||
* @return {ol.expr.Expression} The left expression.
|
||||
*/
|
||||
ol.expr.Comparison.prototype.getLeft = function() {
|
||||
return this.left_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get the right expression.
|
||||
* @return {ol.expr.Expression} The right expression.
|
||||
*/
|
||||
ol.expr.Comparison.prototype.getRight = function() {
|
||||
return this.right_;
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* An identifier expression (e.g. `foo`).
|
||||
*
|
||||
* @constructor
|
||||
* @extends {ol.expr.Expression}
|
||||
* @param {string} name An identifier name.
|
||||
*/
|
||||
ol.expr.Identifier = function(name) {
|
||||
|
||||
/**
|
||||
* @type {string}
|
||||
* @private
|
||||
*/
|
||||
this.name_ = name;
|
||||
|
||||
};
|
||||
goog.inherits(ol.expr.Identifier, ol.expr.Expression);
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
ol.expr.Identifier.prototype.evaluate = function(opt_scope) {
|
||||
if (!goog.isDefAndNotNull(opt_scope)) {
|
||||
throw new Error('Attempt to evaluate identifier with no scope');
|
||||
}
|
||||
return opt_scope[this.name_];
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get the identifier name.
|
||||
* @return {string} The identifier name.
|
||||
*/
|
||||
ol.expr.Identifier.prototype.getName = function() {
|
||||
return this.name_;
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* A literal expression (e.g. `"chicken"`, `42`, `true`, `null`).
|
||||
*
|
||||
* @constructor
|
||||
* @extends {ol.expr.Expression}
|
||||
* @param {string|number|boolean|Date|null} value A literal value.
|
||||
*/
|
||||
ol.expr.Literal = function(value) {
|
||||
|
||||
/**
|
||||
* @type {string|number|boolean|Date|null}
|
||||
* @private
|
||||
*/
|
||||
this.value_ = value;
|
||||
|
||||
};
|
||||
goog.inherits(ol.expr.Literal, ol.expr.Expression);
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
ol.expr.Literal.prototype.evaluate = function() {
|
||||
return this.value_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get the literal value.
|
||||
* @return {string|number|boolean|Date|null} The literal value.
|
||||
*/
|
||||
ol.expr.Literal.prototype.getValue = function() {
|
||||
return this.value_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @enum {string}
|
||||
*/
|
||||
ol.expr.LogicalOp = {
|
||||
AND: '&&',
|
||||
OR: '||'
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* A binary logical expression (e.g. `foo && bar`, `bar || "chicken"`).
|
||||
*
|
||||
* @constructor
|
||||
* @extends {ol.expr.Expression}
|
||||
* @param {ol.expr.LogicalOp} operator Logical operator.
|
||||
* @param {ol.expr.Expression} left Left expression.
|
||||
* @param {ol.expr.Expression} right Right expression.
|
||||
*/
|
||||
ol.expr.Logical = function(operator, left, right) {
|
||||
|
||||
/**
|
||||
* @type {ol.expr.LogicalOp}
|
||||
* @private
|
||||
*/
|
||||
this.operator_ = operator;
|
||||
|
||||
/**
|
||||
* @type {ol.expr.Expression}
|
||||
* @private
|
||||
*/
|
||||
this.left_ = left;
|
||||
|
||||
/**
|
||||
* @type {ol.expr.Expression}
|
||||
* @private
|
||||
*/
|
||||
this.right_ = right;
|
||||
|
||||
};
|
||||
goog.inherits(ol.expr.Logical, ol.expr.Expression);
|
||||
|
||||
|
||||
/**
|
||||
* Determine if a given string is a valid logical operator.
|
||||
* @param {string} candidate Operator to test.
|
||||
* @return {boolean} The operator is valid.
|
||||
*/
|
||||
ol.expr.Logical.isValidOp = (function() {
|
||||
var valid = {};
|
||||
for (var key in ol.expr.LogicalOp) {
|
||||
valid[ol.expr.LogicalOp[key]] = true;
|
||||
}
|
||||
return function isValidOp(candidate) {
|
||||
return !!valid[candidate];
|
||||
};
|
||||
}());
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
ol.expr.Logical.prototype.evaluate = function(opt_scope, opt_fns,
|
||||
opt_this) {
|
||||
var result;
|
||||
var rightVal = this.right_.evaluate(opt_scope, opt_fns, opt_this);
|
||||
var leftVal = this.left_.evaluate(opt_scope, opt_fns, opt_this);
|
||||
|
||||
if (this.operator_ === ol.expr.LogicalOp.AND) {
|
||||
result = leftVal && rightVal;
|
||||
} else if (this.operator_ === ol.expr.LogicalOp.OR) {
|
||||
result = leftVal || rightVal;
|
||||
} else {
|
||||
throw new Error('Unsupported logical operator: ' + this.operator_);
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get the logical operator.
|
||||
* @return {string} The logical operator.
|
||||
*/
|
||||
ol.expr.Logical.prototype.getOperator = function() {
|
||||
return this.operator_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get the left expression.
|
||||
* @return {ol.expr.Expression} The left expression.
|
||||
*/
|
||||
ol.expr.Logical.prototype.getLeft = function() {
|
||||
return this.left_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get the right expression.
|
||||
* @return {ol.expr.Expression} The right expression.
|
||||
*/
|
||||
ol.expr.Logical.prototype.getRight = function() {
|
||||
return this.right_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @enum {string}
|
||||
*/
|
||||
ol.expr.MathOp = {
|
||||
ADD: '+',
|
||||
SUBTRACT: '-',
|
||||
MULTIPLY: '*',
|
||||
DIVIDE: '/',
|
||||
MOD: '%'
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* A math expression (e.g. `foo + 42`, `bar % 10`).
|
||||
*
|
||||
* @constructor
|
||||
* @extends {ol.expr.Expression}
|
||||
* @param {ol.expr.MathOp} operator Math operator.
|
||||
* @param {ol.expr.Expression} left Left expression.
|
||||
* @param {ol.expr.Expression} right Right expression.
|
||||
*/
|
||||
ol.expr.Math = function(operator, left, right) {
|
||||
|
||||
/**
|
||||
* @type {ol.expr.MathOp}
|
||||
* @private
|
||||
*/
|
||||
this.operator_ = operator;
|
||||
|
||||
/**
|
||||
* @type {ol.expr.Expression}
|
||||
* @private
|
||||
*/
|
||||
this.left_ = left;
|
||||
|
||||
/**
|
||||
* @type {ol.expr.Expression}
|
||||
* @private
|
||||
*/
|
||||
this.right_ = right;
|
||||
|
||||
};
|
||||
goog.inherits(ol.expr.Math, ol.expr.Expression);
|
||||
|
||||
|
||||
/**
|
||||
* Determine if a given string is a valid math operator.
|
||||
* @param {string} candidate Operator to test.
|
||||
* @return {boolean} The operator is valid.
|
||||
*/
|
||||
ol.expr.Math.isValidOp = (function() {
|
||||
var valid = {};
|
||||
for (var key in ol.expr.MathOp) {
|
||||
valid[ol.expr.MathOp[key]] = true;
|
||||
}
|
||||
return function isValidOp(candidate) {
|
||||
return !!valid[candidate];
|
||||
};
|
||||
}());
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
ol.expr.Math.prototype.evaluate = function(opt_scope, opt_fns, opt_this) {
|
||||
var result;
|
||||
var rightVal = this.right_.evaluate(opt_scope, opt_fns, opt_this);
|
||||
var leftVal = this.left_.evaluate(opt_scope, opt_fns, opt_this);
|
||||
|
||||
var op = this.operator_;
|
||||
if (op === ol.expr.MathOp.ADD) {
|
||||
result = leftVal + rightVal;
|
||||
} else if (op === ol.expr.MathOp.SUBTRACT) {
|
||||
result = Number(leftVal) - Number(rightVal);
|
||||
} else if (op === ol.expr.MathOp.MULTIPLY) {
|
||||
result = Number(leftVal) * Number(rightVal);
|
||||
} else if (op === ol.expr.MathOp.DIVIDE) {
|
||||
result = Number(leftVal) / Number(rightVal);
|
||||
} else if (op === ol.expr.MathOp.MOD) {
|
||||
result = Number(leftVal) % Number(rightVal);
|
||||
} else {
|
||||
throw new Error('Unsupported math operator: ' + this.operator_);
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get the math operator.
|
||||
* @return {string} The math operator.
|
||||
*/
|
||||
ol.expr.Math.prototype.getOperator = function() {
|
||||
return this.operator_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get the left expression.
|
||||
* @return {ol.expr.Expression} The left expression.
|
||||
*/
|
||||
ol.expr.Math.prototype.getLeft = function() {
|
||||
return this.left_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get the right expression.
|
||||
* @return {ol.expr.Expression} The right expression.
|
||||
*/
|
||||
ol.expr.Math.prototype.getRight = function() {
|
||||
return this.right_;
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* A member expression (e.g. `foo.bar`).
|
||||
*
|
||||
* @constructor
|
||||
* @extends {ol.expr.Expression}
|
||||
* @param {ol.expr.Expression} object An expression that resolves to an
|
||||
* object.
|
||||
* @param {ol.expr.Identifier} property Identifier with name of property.
|
||||
*/
|
||||
ol.expr.Member = function(object, property) {
|
||||
|
||||
/**
|
||||
* @type {ol.expr.Expression}
|
||||
* @private
|
||||
*/
|
||||
this.object_ = object;
|
||||
|
||||
/**
|
||||
* @type {ol.expr.Identifier}
|
||||
* @private
|
||||
*/
|
||||
this.property_ = property;
|
||||
|
||||
};
|
||||
goog.inherits(ol.expr.Member, ol.expr.Expression);
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
ol.expr.Member.prototype.evaluate = function(opt_scope, opt_fns,
|
||||
opt_this) {
|
||||
var obj = this.object_.evaluate(opt_scope, opt_fns, opt_this);
|
||||
if (!goog.isObject(obj)) {
|
||||
throw new Error('Expected member expression to evaluate to an object ' +
|
||||
'but got ' + obj);
|
||||
}
|
||||
return this.property_.evaluate(/** @type {Object} */ (obj));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get the object expression.
|
||||
* @return {ol.expr.Expression} The object.
|
||||
*/
|
||||
ol.expr.Member.prototype.getObject = function() {
|
||||
return this.object_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get the property expression.
|
||||
* @return {ol.expr.Identifier} The property.
|
||||
*/
|
||||
ol.expr.Member.prototype.getProperty = function() {
|
||||
return this.property_;
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* A logical not expression (e.g. `!foo`).
|
||||
*
|
||||
* @constructor
|
||||
* @extends {ol.expr.Expression}
|
||||
* @param {ol.expr.Expression} argument Expression to negate.
|
||||
*/
|
||||
ol.expr.Not = function(argument) {
|
||||
|
||||
/**
|
||||
* @type {ol.expr.Expression}
|
||||
* @private
|
||||
*/
|
||||
this.argument_ = argument;
|
||||
|
||||
};
|
||||
goog.inherits(ol.expr.Not, ol.expr.Expression);
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
ol.expr.Not.prototype.evaluate = function(opt_scope, opt_fns, opt_this) {
|
||||
return !this.argument_.evaluate(opt_scope, opt_fns, opt_this);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get the argument (the negated expression).
|
||||
* @return {ol.expr.Expression} The argument.
|
||||
*/
|
||||
ol.expr.Not.prototype.getArgument = function() {
|
||||
return this.argument_;
|
||||
};
|
||||
@@ -0,0 +1,900 @@
|
||||
/**
|
||||
* The logic and naming of methods here are inspired by Esprima (BSD Licensed).
|
||||
* Esprima (http://esprima.org) includes the following copyright notices:
|
||||
*
|
||||
* Copyright (C) 2013 Ariya Hidayat <ariya.hidayat@gmail.com>
|
||||
* Copyright (C) 2013 Thaddee Tyl <thaddee.tyl@gmail.com>
|
||||
* Copyright (C) 2012 Ariya Hidayat <ariya.hidayat@gmail.com>
|
||||
* Copyright (C) 2012 Mathias Bynens <mathias@qiwi.be>
|
||||
* Copyright (C) 2012 Joost-Wim Boekesteijn <joost-wim@boekesteijn.nl>
|
||||
* Copyright (C) 2012 Kris Kowal <kris.kowal@cixar.com>
|
||||
* Copyright (C) 2012 Yusuke Suzuki <utatane.tea@gmail.com>
|
||||
* Copyright (C) 2012 Arpad Borsos <arpad.borsos@googlemail.com>
|
||||
* Copyright (C) 2011 Ariya Hidayat <ariya.hidayat@gmail.com>
|
||||
*/
|
||||
|
||||
goog.provide('ol.expr.Char'); // TODO: remove this - see #785
|
||||
goog.provide('ol.expr.Lexer');
|
||||
goog.provide('ol.expr.Token');
|
||||
goog.provide('ol.expr.TokenType');
|
||||
goog.provide('ol.expr.UnexpectedToken');
|
||||
|
||||
goog.require('goog.asserts');
|
||||
goog.require('goog.debug.Error');
|
||||
|
||||
|
||||
/**
|
||||
* @enum {number}
|
||||
*/
|
||||
ol.expr.Char = {
|
||||
AMPERSAND: 38,
|
||||
BACKSLASH: 92,
|
||||
BANG: 33, // !
|
||||
CARRIAGE_RETURN: 13,
|
||||
COMMA: 44,
|
||||
DIGIT_0: 48,
|
||||
DIGIT_7: 55,
|
||||
DIGIT_9: 57,
|
||||
DOLLAR: 36,
|
||||
DOUBLE_QUOTE: 34,
|
||||
DOT: 46,
|
||||
EQUAL: 61,
|
||||
FORM_FEED: 0xC,
|
||||
GREATER: 62,
|
||||
LEFT_PAREN: 40,
|
||||
LESS: 60,
|
||||
LINE_FEED: 10,
|
||||
LINE_SEPARATOR: 0x2028,
|
||||
LOWER_A: 97,
|
||||
LOWER_E: 101,
|
||||
LOWER_F: 102,
|
||||
LOWER_X: 120,
|
||||
LOWER_Z: 122,
|
||||
MINUS: 45,
|
||||
NONBREAKING_SPACE: 0xA0,
|
||||
PARAGRAPH_SEPARATOR: 0x2029,
|
||||
PERCENT: 37,
|
||||
PIPE: 124,
|
||||
PLUS: 43,
|
||||
RIGHT_PAREN: 41,
|
||||
SINGLE_QUOTE: 39,
|
||||
SLASH: 47,
|
||||
SPACE: 32,
|
||||
STAR: 42,
|
||||
TAB: 9,
|
||||
TILDE: 126,
|
||||
UNDERSCORE: 95,
|
||||
UPPER_A: 65,
|
||||
UPPER_E: 69,
|
||||
UPPER_F: 70,
|
||||
UPPER_X: 88,
|
||||
UPPER_Z: 90,
|
||||
VERTICAL_TAB: 0xB
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @enum {string}
|
||||
*/
|
||||
ol.expr.TokenType = {
|
||||
BOOLEAN_LITERAL: 'Boolean',
|
||||
EOF: '<end>',
|
||||
IDENTIFIER: 'Identifier',
|
||||
KEYWORD: 'Keyword',
|
||||
NULL_LITERAL: 'Null',
|
||||
NUMERIC_LITERAL: 'Numeric',
|
||||
PUNCTUATOR: 'Punctuator',
|
||||
STRING_LITERAL: 'String',
|
||||
UNKNOWN: 'Unknown'
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @typedef {{type: (ol.expr.TokenType),
|
||||
* value: (string|number|boolean|null),
|
||||
* index: (number)}}
|
||||
*/
|
||||
ol.expr.Token;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Lexer constructor. Provides a tokenizer for a limited subset of ECMAScript
|
||||
* 5.1 expressions (http://www.ecma-international.org/ecma-262/5.1/#sec-11).
|
||||
*
|
||||
* @constructor
|
||||
* @param {string} source Source code.
|
||||
*/
|
||||
ol.expr.Lexer = function(source) {
|
||||
|
||||
/**
|
||||
* Source code.
|
||||
* @type {string}
|
||||
* @private
|
||||
*/
|
||||
this.source_ = source;
|
||||
|
||||
/**
|
||||
* Source length.
|
||||
* @type {number}
|
||||
* @private
|
||||
*/
|
||||
this.length_ = source.length;
|
||||
|
||||
/**
|
||||
* Current character index.
|
||||
* @type {number}
|
||||
* @private
|
||||
*/
|
||||
this.index_ = 0;
|
||||
|
||||
/**
|
||||
* Next character index (only set after `peek`ing).
|
||||
* @type {number}
|
||||
* @private
|
||||
*/
|
||||
this.nextIndex_ = 0;
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Scan the next token and throw if it isn't a punctuator that matches input.
|
||||
* @param {string} value Token value.
|
||||
*/
|
||||
ol.expr.Lexer.prototype.expect = function(value) {
|
||||
var match = this.match(value);
|
||||
if (!match) {
|
||||
throw new ol.expr.UnexpectedToken({
|
||||
type: ol.expr.TokenType.UNKNOWN,
|
||||
value: this.getCurrentChar_(),
|
||||
index: this.index_
|
||||
});
|
||||
}
|
||||
this.skip();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Increment the current character index.
|
||||
*
|
||||
* @param {number} delta Delta by which the index is advanced.
|
||||
* @private
|
||||
*/
|
||||
ol.expr.Lexer.prototype.increment_ = function(delta) {
|
||||
this.index_ += delta;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* http://www.ecma-international.org/ecma-262/5.1/#sec-7.8.3
|
||||
*
|
||||
* @param {number} code The unicode of a character.
|
||||
* @return {boolean} The character is a decimal digit.
|
||||
* @private
|
||||
*/
|
||||
ol.expr.Lexer.prototype.isDecimalDigit_ = function(code) {
|
||||
return (
|
||||
code >= ol.expr.Char.DIGIT_0 &&
|
||||
code <= ol.expr.Char.DIGIT_9);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* http://www.ecma-international.org/ecma-262/5.1/#sec-7.6.1.2
|
||||
*
|
||||
* @param {string} id A string identifier.
|
||||
* @return {boolean} The identifier is a future reserved word.
|
||||
* @private
|
||||
*/
|
||||
ol.expr.Lexer.prototype.isFutureReservedWord_ = function(id) {
|
||||
return (
|
||||
id === 'class' ||
|
||||
id === 'enum' ||
|
||||
id === 'export' ||
|
||||
id === 'extends' ||
|
||||
id === 'import' ||
|
||||
id === 'super');
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* http://www.ecma-international.org/ecma-262/5.1/#sec-7.8.3
|
||||
*
|
||||
* @param {number} code The unicode of a character.
|
||||
* @return {boolean} The character is a hex digit.
|
||||
* @private
|
||||
*/
|
||||
ol.expr.Lexer.prototype.isHexDigit_ = function(code) {
|
||||
return this.isDecimalDigit_(code) ||
|
||||
(code >= ol.expr.Char.LOWER_A &&
|
||||
code <= ol.expr.Char.LOWER_F) ||
|
||||
(code >= ol.expr.Char.UPPER_A &&
|
||||
code <= ol.expr.Char.UPPER_F);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* http://www.ecma-international.org/ecma-262/5.1/#sec-7.6
|
||||
* Doesn't deal with non-ascii identifiers.
|
||||
*
|
||||
* @param {number} code The unicode of a character.
|
||||
* @return {boolean} The character is a valid identifier part.
|
||||
* @private
|
||||
*/
|
||||
ol.expr.Lexer.prototype.isIdentifierPart_ = function(code) {
|
||||
return this.isIdentifierStart_(code) ||
|
||||
(code >= ol.expr.Char.DIGIT_0 &&
|
||||
code <= ol.expr.Char.DIGIT_9);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* http://www.ecma-international.org/ecma-262/5.1/#sec-7.6
|
||||
* Doesn't yet deal with non-ascii identifiers.
|
||||
*
|
||||
* @param {number} code The unicode of a character.
|
||||
* @return {boolean} The character is a valid identifier start.
|
||||
* @private
|
||||
*/
|
||||
ol.expr.Lexer.prototype.isIdentifierStart_ = function(code) {
|
||||
return (code === ol.expr.Char.DOLLAR) ||
|
||||
(code === ol.expr.Char.UNDERSCORE) ||
|
||||
(code >= ol.expr.Char.UPPER_A &&
|
||||
code <= ol.expr.Char.UPPER_Z) ||
|
||||
(code >= ol.expr.Char.LOWER_A &&
|
||||
code <= ol.expr.Char.LOWER_Z);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Determine if the given identifier is an ECMAScript keyword. These cannot
|
||||
* be used as identifiers in programs. There is no real reason these could not
|
||||
* be used in ol.exprs - but they are reserved for future use.
|
||||
*
|
||||
* http://www.ecma-international.org/ecma-262/5.1/#sec-7.6.1.1
|
||||
*
|
||||
* @param {string} id Identifier.
|
||||
* @return {boolean} The identifier is a keyword.
|
||||
* @private
|
||||
*/
|
||||
ol.expr.Lexer.prototype.isKeyword_ = function(id) {
|
||||
return (
|
||||
id === 'break' ||
|
||||
id === 'case' ||
|
||||
id === 'catch' ||
|
||||
id === 'continue' ||
|
||||
id === 'debugger' ||
|
||||
id === 'default' ||
|
||||
id === 'delete' ||
|
||||
id === 'do' ||
|
||||
id === 'else' ||
|
||||
id === 'finally' ||
|
||||
id === 'for' ||
|
||||
id === 'function' ||
|
||||
id === 'if' ||
|
||||
id === 'in' ||
|
||||
id === 'instanceof' ||
|
||||
id === 'new' ||
|
||||
id === 'return' ||
|
||||
id === 'switch' ||
|
||||
id === 'this' ||
|
||||
id === 'throw' ||
|
||||
id === 'try' ||
|
||||
id === 'typeof' ||
|
||||
id === 'var' ||
|
||||
id === 'void' ||
|
||||
id === 'while' ||
|
||||
id === 'with');
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* http://www.ecma-international.org/ecma-262/5.1/#sec-7.3
|
||||
*
|
||||
* @param {number} code The unicode of a character.
|
||||
* @return {boolean} The character is a line terminator.
|
||||
* @private
|
||||
*/
|
||||
ol.expr.Lexer.prototype.isLineTerminator_ = function(code) {
|
||||
return (code === ol.expr.Char.LINE_FEED) ||
|
||||
(code === ol.expr.Char.CARRIAGE_RETURN) ||
|
||||
(code === ol.expr.Char.LINE_SEPARATOR) ||
|
||||
(code === ol.expr.Char.PARAGRAPH_SEPARATOR);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* http://www.ecma-international.org/ecma-262/5.1/#sec-7.8.3
|
||||
*
|
||||
* @param {number} code The unicode of a character.
|
||||
* @return {boolean} The character is an octal digit.
|
||||
* @private
|
||||
*/
|
||||
ol.expr.Lexer.prototype.isOctalDigit_ = function(code) {
|
||||
return (
|
||||
code >= ol.expr.Char.DIGIT_0 &&
|
||||
code <= ol.expr.Char.DIGIT_7);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* http://www.ecma-international.org/ecma-262/5.1/#sec-7.2
|
||||
*
|
||||
* @param {number} code The unicode of a character.
|
||||
* @return {boolean} The character is whitespace.
|
||||
* @private
|
||||
*/
|
||||
ol.expr.Lexer.prototype.isWhitespace_ = function(code) {
|
||||
return (code === ol.expr.Char.SPACE) ||
|
||||
(code === ol.expr.Char.TAB) ||
|
||||
(code === ol.expr.Char.VERTICAL_TAB) ||
|
||||
(code === ol.expr.Char.FORM_FEED) ||
|
||||
(code === ol.expr.Char.NONBREAKING_SPACE) ||
|
||||
(code >= 0x1680 && '\u1680\u180E\u2000\u2001\u2002\u2003\u2004\u2005' +
|
||||
'\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u3000\uFEFF'
|
||||
.indexOf(String.fromCharCode(code)) > 0);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get the unicode of the character at the given offset from the current index.
|
||||
*
|
||||
* @param {number} delta Offset from current index.
|
||||
* @return {number} The character code.
|
||||
* @private
|
||||
*/
|
||||
ol.expr.Lexer.prototype.getCharCode_ = function(delta) {
|
||||
return this.source_.charCodeAt(this.index_ + delta);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get the character at the current index.
|
||||
*
|
||||
* @return {string} The current character.
|
||||
* @private
|
||||
*/
|
||||
ol.expr.Lexer.prototype.getCurrentChar_ = function() {
|
||||
return this.source_[this.index_];
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get the unicode of the character at the current index.
|
||||
*
|
||||
* @return {number} The current character code.
|
||||
* @private
|
||||
*/
|
||||
ol.expr.Lexer.prototype.getCurrentCharCode_ = function() {
|
||||
return this.getCharCode_(0);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Determine whether the upcoming token matches the given punctuator.
|
||||
* @param {string} value Punctuator value.
|
||||
* @return {boolean} The token matches.
|
||||
*/
|
||||
ol.expr.Lexer.prototype.match = function(value) {
|
||||
var token = this.peek();
|
||||
return (
|
||||
token.type === ol.expr.TokenType.PUNCTUATOR &&
|
||||
token.value === value);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Scan the next token.
|
||||
*
|
||||
* @return {ol.expr.Token} Next token.
|
||||
*/
|
||||
ol.expr.Lexer.prototype.next = function() {
|
||||
var code = this.skipWhitespace_();
|
||||
|
||||
if (this.index_ >= this.length_) {
|
||||
return {
|
||||
type: ol.expr.TokenType.EOF,
|
||||
value: null,
|
||||
index: this.index_
|
||||
};
|
||||
}
|
||||
|
||||
// check for common punctuation
|
||||
if (code === ol.expr.Char.LEFT_PAREN ||
|
||||
code === ol.expr.Char.RIGHT_PAREN) {
|
||||
return this.scanPunctuator_(code);
|
||||
}
|
||||
|
||||
// check for string literal
|
||||
if (code === ol.expr.Char.SINGLE_QUOTE ||
|
||||
code === ol.expr.Char.DOUBLE_QUOTE) {
|
||||
return this.scanStringLiteral_(code);
|
||||
}
|
||||
|
||||
// check for identifier
|
||||
if (this.isIdentifierStart_(code)) {
|
||||
return this.scanIdentifier_(code);
|
||||
}
|
||||
|
||||
// check dot punctuation or decimal
|
||||
if (code === ol.expr.Char.DOT) {
|
||||
if (this.isDecimalDigit_(this.getCharCode_(1))) {
|
||||
return this.scanNumericLiteral_(code);
|
||||
}
|
||||
return this.scanPunctuator_(code);
|
||||
}
|
||||
|
||||
// check for numeric literal
|
||||
if (this.isDecimalDigit_(code)) {
|
||||
return this.scanNumericLiteral_(code);
|
||||
}
|
||||
|
||||
// all the rest is punctuation
|
||||
return this.scanPunctuator_(code);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Peek at the next token, but don't advance the index.
|
||||
*
|
||||
* @return {ol.expr.Token} The upcoming token.
|
||||
*/
|
||||
ol.expr.Lexer.prototype.peek = function() {
|
||||
var currentIndex = this.index_;
|
||||
var token = this.next();
|
||||
this.nextIndex_ = this.index_;
|
||||
this.index_ = currentIndex;
|
||||
return token;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Scan hex literal as numeric token.
|
||||
*
|
||||
* @param {number} code The current character code.
|
||||
* @return {ol.expr.Token} Numeric literal token.
|
||||
* @private
|
||||
*/
|
||||
ol.expr.Lexer.prototype.scanHexLiteral_ = function(code) {
|
||||
var str = '';
|
||||
var start = this.index_ - 2;
|
||||
|
||||
while (this.index_ < this.length_) {
|
||||
if (!this.isHexDigit_(code)) {
|
||||
break;
|
||||
}
|
||||
str += String.fromCharCode(code);
|
||||
this.increment_(1);
|
||||
code = this.getCurrentCharCode_();
|
||||
}
|
||||
|
||||
if (str.length === 0 || this.isIdentifierStart_(code)) {
|
||||
throw new ol.expr.UnexpectedToken({
|
||||
type: ol.expr.TokenType.UNKNOWN,
|
||||
value: String.fromCharCode(code),
|
||||
index: this.index_
|
||||
});
|
||||
}
|
||||
|
||||
goog.asserts.assert(!isNaN(parseInt('0x' + str, 16)), 'Valid hex: ' + str);
|
||||
|
||||
return {
|
||||
type: ol.expr.TokenType.NUMERIC_LITERAL,
|
||||
value: parseInt('0x' + str, 16),
|
||||
index: start
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Scan identifier token.
|
||||
*
|
||||
* @param {number} code The current character code.
|
||||
* @return {ol.expr.Token} Identifier token.
|
||||
* @private
|
||||
*/
|
||||
ol.expr.Lexer.prototype.scanIdentifier_ = function(code) {
|
||||
goog.asserts.assert(this.isIdentifierStart_(code),
|
||||
'Must be called with a valid identifier');
|
||||
|
||||
var start = this.index_;
|
||||
this.increment_(1);
|
||||
|
||||
while (this.index_ < this.length_) {
|
||||
code = this.getCurrentCharCode_();
|
||||
if (this.isIdentifierPart_(code)) {
|
||||
this.increment_(1);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
var id = this.source_.slice(start, this.index_);
|
||||
|
||||
var type;
|
||||
if (id.length === 1) {
|
||||
type = ol.expr.TokenType.IDENTIFIER;
|
||||
} else if (this.isKeyword_(id)) {
|
||||
type = ol.expr.TokenType.KEYWORD;
|
||||
} else if (id === 'null') {
|
||||
type = ol.expr.TokenType.NULL_LITERAL;
|
||||
} else if (id === 'true' || id === 'false') {
|
||||
type = ol.expr.TokenType.BOOLEAN_LITERAL;
|
||||
} else {
|
||||
type = ol.expr.TokenType.IDENTIFIER;
|
||||
}
|
||||
|
||||
return {
|
||||
type: type,
|
||||
value: id,
|
||||
index: start
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Scan numeric literal token.
|
||||
* http://www.ecma-international.org/ecma-262/5.1/#sec-7.8.3
|
||||
*
|
||||
* @param {number} code The current character code.
|
||||
* @return {ol.expr.Token} Numeric literal token.
|
||||
* @private
|
||||
*/
|
||||
ol.expr.Lexer.prototype.scanNumericLiteral_ = function(code) {
|
||||
goog.asserts.assert(
|
||||
code === ol.expr.Char.DOT || this.isDecimalDigit_(code),
|
||||
'Valid start for numeric literal: ' + String.fromCharCode(code));
|
||||
|
||||
// start assembling numeric string
|
||||
var str = '';
|
||||
var start = this.index_;
|
||||
|
||||
if (code !== ol.expr.Char.DOT) {
|
||||
|
||||
if (code === ol.expr.Char.DIGIT_0) {
|
||||
var nextCode = this.getCharCode_(1);
|
||||
|
||||
// hex literals start with 0X or 0x
|
||||
if (nextCode === ol.expr.Char.UPPER_X ||
|
||||
nextCode === ol.expr.Char.LOWER_X) {
|
||||
this.increment_(2);
|
||||
return this.scanHexLiteral_(this.getCurrentCharCode_());
|
||||
}
|
||||
|
||||
// octals start with 0
|
||||
if (this.isOctalDigit_(nextCode)) {
|
||||
this.increment_(1);
|
||||
return this.scanOctalLiteral_(nextCode);
|
||||
}
|
||||
|
||||
// numbers like 09 not allowed
|
||||
if (this.isDecimalDigit_(nextCode)) {
|
||||
throw new ol.expr.UnexpectedToken({
|
||||
type: ol.expr.TokenType.UNKNOWN,
|
||||
value: String.fromCharCode(nextCode),
|
||||
index: this.index_
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// scan all decimal chars
|
||||
while (this.isDecimalDigit_(code)) {
|
||||
str += String.fromCharCode(code);
|
||||
this.increment_(1);
|
||||
code = this.getCurrentCharCode_();
|
||||
}
|
||||
}
|
||||
|
||||
// scan fractional part
|
||||
if (code === ol.expr.Char.DOT) {
|
||||
str += String.fromCharCode(code);
|
||||
this.increment_(1);
|
||||
code = this.getCurrentCharCode_();
|
||||
|
||||
// scan all decimal chars
|
||||
while (this.isDecimalDigit_(code)) {
|
||||
str += String.fromCharCode(code);
|
||||
this.increment_(1);
|
||||
code = this.getCurrentCharCode_();
|
||||
}
|
||||
}
|
||||
|
||||
// scan exponent
|
||||
if (code === ol.expr.Char.UPPER_E ||
|
||||
code === ol.expr.Char.LOWER_E) {
|
||||
str += 'E';
|
||||
this.increment_(1);
|
||||
|
||||
code = this.getCurrentCharCode_();
|
||||
if (code === ol.expr.Char.PLUS ||
|
||||
code === ol.expr.Char.MINUS) {
|
||||
str += String.fromCharCode(code);
|
||||
this.increment_(1);
|
||||
code = this.getCurrentCharCode_();
|
||||
}
|
||||
|
||||
if (!this.isDecimalDigit_(code)) {
|
||||
throw new ol.expr.UnexpectedToken({
|
||||
type: ol.expr.TokenType.UNKNOWN,
|
||||
value: String.fromCharCode(code),
|
||||
index: this.index_
|
||||
});
|
||||
}
|
||||
|
||||
// scan all decimal chars (TODO: unduplicate this)
|
||||
while (this.isDecimalDigit_(code)) {
|
||||
str += String.fromCharCode(code);
|
||||
this.increment_(1);
|
||||
code = this.getCurrentCharCode_();
|
||||
}
|
||||
}
|
||||
|
||||
if (this.isIdentifierStart_(code)) {
|
||||
throw new ol.expr.UnexpectedToken({
|
||||
type: ol.expr.TokenType.UNKNOWN,
|
||||
value: String.fromCharCode(code),
|
||||
index: this.index_
|
||||
});
|
||||
}
|
||||
|
||||
goog.asserts.assert(!isNaN(parseFloat(str)), 'Valid number: ' + str);
|
||||
|
||||
return {
|
||||
type: ol.expr.TokenType.NUMERIC_LITERAL,
|
||||
value: parseFloat(str),
|
||||
index: start
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Scan octal literal as numeric token.
|
||||
*
|
||||
* @param {number} code The current character code.
|
||||
* @return {ol.expr.Token} Numeric literal token.
|
||||
* @private
|
||||
*/
|
||||
ol.expr.Lexer.prototype.scanOctalLiteral_ = function(code) {
|
||||
goog.asserts.assert(this.isOctalDigit_(code));
|
||||
|
||||
var str = '0' + String.fromCharCode(code);
|
||||
var start = this.index_ - 1;
|
||||
this.increment_(1);
|
||||
|
||||
while (this.index_ < this.length_) {
|
||||
code = this.getCurrentCharCode_();
|
||||
if (!this.isOctalDigit_(code)) {
|
||||
break;
|
||||
}
|
||||
str += String.fromCharCode(code);
|
||||
this.increment_(1);
|
||||
}
|
||||
|
||||
code = this.getCurrentCharCode_();
|
||||
if (this.isIdentifierStart_(code) ||
|
||||
this.isDecimalDigit_(code)) {
|
||||
throw new ol.expr.UnexpectedToken({
|
||||
type: ol.expr.TokenType.UNKNOWN,
|
||||
value: String.fromCharCode(code),
|
||||
index: this.index_
|
||||
});
|
||||
}
|
||||
|
||||
goog.asserts.assert(!isNaN(parseInt(str, 8)), 'Valid octal: ' + str);
|
||||
|
||||
return {
|
||||
type: ol.expr.TokenType.NUMERIC_LITERAL,
|
||||
value: parseInt(str, 8),
|
||||
index: start
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Scan punctuator token (a subset of allowed tokens in 7.7).
|
||||
*
|
||||
* @param {number} code The current character code.
|
||||
* @return {ol.expr.Token} Punctuator token.
|
||||
* @private
|
||||
*/
|
||||
ol.expr.Lexer.prototype.scanPunctuator_ = function(code) {
|
||||
var start = this.index_;
|
||||
|
||||
// single char punctuation that also doesn't start longer punctuation
|
||||
// (we disallow assignment, so no += etc.)
|
||||
if (code === ol.expr.Char.DOT ||
|
||||
code === ol.expr.Char.LEFT_PAREN ||
|
||||
code === ol.expr.Char.RIGHT_PAREN ||
|
||||
code === ol.expr.Char.COMMA ||
|
||||
code === ol.expr.Char.PLUS ||
|
||||
code === ol.expr.Char.MINUS ||
|
||||
code === ol.expr.Char.STAR ||
|
||||
code === ol.expr.Char.SLASH ||
|
||||
code === ol.expr.Char.PERCENT ||
|
||||
code === ol.expr.Char.TILDE) {
|
||||
|
||||
this.increment_(1);
|
||||
return {
|
||||
type: ol.expr.TokenType.PUNCTUATOR,
|
||||
value: String.fromCharCode(code),
|
||||
index: start
|
||||
};
|
||||
}
|
||||
|
||||
// check for 2-character punctuation
|
||||
var nextCode = this.getCharCode_(1);
|
||||
|
||||
// assignment or comparison (and we don't allow assignment)
|
||||
if (nextCode === ol.expr.Char.EQUAL) {
|
||||
if (code === ol.expr.Char.BANG || code === ol.expr.Char.EQUAL) {
|
||||
// we're looking at !=, ==, !==, or ===
|
||||
this.increment_(2);
|
||||
|
||||
// check for triple
|
||||
if (this.getCurrentCharCode_() === ol.expr.Char.EQUAL) {
|
||||
this.increment_(1);
|
||||
return {
|
||||
type: ol.expr.TokenType.PUNCTUATOR,
|
||||
value: String.fromCharCode(code) + '==',
|
||||
index: start
|
||||
};
|
||||
} else {
|
||||
// != or ==
|
||||
return {
|
||||
type: ol.expr.TokenType.PUNCTUATOR,
|
||||
value: String.fromCharCode(code) + '=',
|
||||
index: start
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
if (code === ol.expr.Char.GREATER ||
|
||||
code === ol.expr.Char.LESS) {
|
||||
this.increment_(2);
|
||||
return {
|
||||
type: ol.expr.TokenType.PUNCTUATOR,
|
||||
value: String.fromCharCode(code) + '=',
|
||||
index: start
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// remaining 2-charcter punctuators are || and &&
|
||||
if (code === nextCode &&
|
||||
(code === ol.expr.Char.PIPE ||
|
||||
code === ol.expr.Char.AMPERSAND)) {
|
||||
|
||||
this.increment_(2);
|
||||
var str = String.fromCharCode(code);
|
||||
return {
|
||||
type: ol.expr.TokenType.PUNCTUATOR,
|
||||
value: str + str,
|
||||
index: start
|
||||
};
|
||||
}
|
||||
|
||||
// we don't allow 4-character punctuator (>>>=)
|
||||
// and the allowed 3-character punctuators (!==, ===) are already consumed
|
||||
|
||||
// other single character punctuators
|
||||
if (code === ol.expr.Char.GREATER ||
|
||||
code === ol.expr.Char.LESS ||
|
||||
code === ol.expr.Char.BANG ||
|
||||
code === ol.expr.Char.AMPERSAND ||
|
||||
code === ol.expr.Char.PIPE) {
|
||||
|
||||
this.increment_(1);
|
||||
return {
|
||||
type: ol.expr.TokenType.PUNCTUATOR,
|
||||
value: String.fromCharCode(code),
|
||||
index: start
|
||||
};
|
||||
}
|
||||
|
||||
throw new ol.expr.UnexpectedToken({
|
||||
type: ol.expr.TokenType.UNKNOWN,
|
||||
value: String.fromCharCode(code),
|
||||
index: this.index_
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Scan string literal token.
|
||||
*
|
||||
* @param {number} quote The current character code.
|
||||
* @return {ol.expr.Token} String literal token.
|
||||
* @private
|
||||
*/
|
||||
ol.expr.Lexer.prototype.scanStringLiteral_ = function(quote) {
|
||||
goog.asserts.assert(quote === ol.expr.Char.SINGLE_QUOTE ||
|
||||
quote === ol.expr.Char.DOUBLE_QUOTE,
|
||||
'Strings must start with a quote: ' + String.fromCharCode(quote));
|
||||
|
||||
var start = this.index_;
|
||||
this.increment_(1);
|
||||
|
||||
var str = '';
|
||||
var code;
|
||||
while (this.index_ < this.length_) {
|
||||
code = this.getCurrentCharCode_();
|
||||
this.increment_(1);
|
||||
if (code === quote) {
|
||||
quote = 0;
|
||||
break;
|
||||
}
|
||||
// look for escaped quote or backslash
|
||||
if (code === ol.expr.Char.BACKSLASH) {
|
||||
str += this.getCurrentChar_();
|
||||
this.increment_(1);
|
||||
} else {
|
||||
str += String.fromCharCode(code);
|
||||
}
|
||||
}
|
||||
|
||||
if (quote !== 0) {
|
||||
// unterminated string literal
|
||||
throw new ol.expr.UnexpectedToken(this.peek());
|
||||
}
|
||||
|
||||
return {
|
||||
type: ol.expr.TokenType.STRING_LITERAL,
|
||||
value: str,
|
||||
index: start
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* After peeking, skip may be called to advance the cursor without re-scanning.
|
||||
*/
|
||||
ol.expr.Lexer.prototype.skip = function() {
|
||||
this.index_ = this.nextIndex_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Skip all whitespace.
|
||||
* @return {number} The character code of the first non-whitespace character.
|
||||
* @private
|
||||
*/
|
||||
ol.expr.Lexer.prototype.skipWhitespace_ = function() {
|
||||
var code = NaN;
|
||||
while (this.index_ < this.length_) {
|
||||
code = this.getCurrentCharCode_();
|
||||
if (this.isWhitespace_(code)) {
|
||||
this.increment_(1);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return code;
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Error object for unexpected tokens.
|
||||
* @param {ol.expr.Token} token The unexpected token.
|
||||
* @param {string=} opt_message Custom error message.
|
||||
* @constructor
|
||||
* @extends {goog.debug.Error}
|
||||
*/
|
||||
ol.expr.UnexpectedToken = function(token, opt_message) {
|
||||
var message = goog.isDef(opt_message) ? opt_message :
|
||||
'Unexpected token ' + token.value + ' at index ' + token.index;
|
||||
|
||||
goog.debug.Error.call(this, message);
|
||||
|
||||
/**
|
||||
* @type {ol.expr.Token}
|
||||
*/
|
||||
this.token = token;
|
||||
|
||||
};
|
||||
goog.inherits(ol.expr.UnexpectedToken, goog.debug.Error);
|
||||
|
||||
|
||||
/** @override */
|
||||
ol.expr.UnexpectedToken.prototype.name = 'UnexpectedToken';
|
||||
@@ -0,0 +1,478 @@
|
||||
/**
|
||||
* The logic and naming of methods here are inspired by Esprima (BSD Licensed).
|
||||
* Esprima (http://esprima.org) includes the following copyright notices:
|
||||
*
|
||||
* Copyright (C) 2013 Ariya Hidayat <ariya.hidayat@gmail.com>
|
||||
* Copyright (C) 2013 Thaddee Tyl <thaddee.tyl@gmail.com>
|
||||
* Copyright (C) 2012 Ariya Hidayat <ariya.hidayat@gmail.com>
|
||||
* Copyright (C) 2012 Mathias Bynens <mathias@qiwi.be>
|
||||
* Copyright (C) 2012 Joost-Wim Boekesteijn <joost-wim@boekesteijn.nl>
|
||||
* Copyright (C) 2012 Kris Kowal <kris.kowal@cixar.com>
|
||||
* Copyright (C) 2012 Yusuke Suzuki <utatane.tea@gmail.com>
|
||||
* Copyright (C) 2012 Arpad Borsos <arpad.borsos@googlemail.com>
|
||||
* Copyright (C) 2011 Ariya Hidayat <ariya.hidayat@gmail.com>
|
||||
*/
|
||||
|
||||
goog.provide('ol.expr.Parser');
|
||||
|
||||
goog.require('goog.asserts');
|
||||
|
||||
goog.require('ol.expr.Call');
|
||||
goog.require('ol.expr.Comparison');
|
||||
goog.require('ol.expr.ComparisonOp');
|
||||
goog.require('ol.expr.Expression');
|
||||
goog.require('ol.expr.Identifier');
|
||||
goog.require('ol.expr.Lexer');
|
||||
goog.require('ol.expr.Literal');
|
||||
goog.require('ol.expr.Logical');
|
||||
goog.require('ol.expr.LogicalOp');
|
||||
goog.require('ol.expr.Math');
|
||||
goog.require('ol.expr.MathOp');
|
||||
goog.require('ol.expr.Member');
|
||||
goog.require('ol.expr.Not');
|
||||
goog.require('ol.expr.Token');
|
||||
goog.require('ol.expr.TokenType');
|
||||
goog.require('ol.expr.UnexpectedToken');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Instances of ol.expr.Parser parse a very limited set of ECMAScript
|
||||
* expressions (http://www.ecma-international.org/ecma-262/5.1/#sec-11).
|
||||
*
|
||||
* - Primary Expression (11.1):
|
||||
* - Identifier (e.g. `foo`)
|
||||
* - Literal (e.g. `"some string"` or `42`)
|
||||
* - Grouped (e.g. `(foo)`)
|
||||
* - Left-Hand-Side Expression (11.2):
|
||||
* - Property Accessors
|
||||
* - Dot notation only
|
||||
* - Function Calls
|
||||
* - Identifier with arguments only (e.g. `foo(bar, 42)`)
|
||||
* - Unary Operators (11.4)
|
||||
* - Logical Not (e.g. `!foo`)
|
||||
* - Multiplicitave Operators (11.5)
|
||||
* - Additive Operators (11.6)
|
||||
* - Relational Operators (11.8)
|
||||
* - <, >, <=, and >= only
|
||||
* - Equality Operators (11.9)
|
||||
* - Binary Logical Operators (11.11)
|
||||
*
|
||||
* @constructor
|
||||
*/
|
||||
ol.expr.Parser = function() {
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Determine the precedence for the given token.
|
||||
*
|
||||
* @param {ol.expr.Token} token A token.
|
||||
* @return {number} The precedence for the given token. Higher gets more
|
||||
* precedence.
|
||||
* @private
|
||||
*/
|
||||
ol.expr.Parser.prototype.binaryPrecedence_ = function(token) {
|
||||
var precedence = 0;
|
||||
if (token.type !== ol.expr.TokenType.PUNCTUATOR) {
|
||||
return precedence;
|
||||
}
|
||||
|
||||
switch (token.value) {
|
||||
case ol.expr.LogicalOp.OR:
|
||||
precedence = 1;
|
||||
break;
|
||||
case ol.expr.LogicalOp.AND:
|
||||
precedence = 2;
|
||||
break;
|
||||
case ol.expr.ComparisonOp.EQ:
|
||||
case ol.expr.ComparisonOp.NEQ:
|
||||
case ol.expr.ComparisonOp.STRICT_EQ:
|
||||
case ol.expr.ComparisonOp.STRICT_NEQ:
|
||||
precedence = 3;
|
||||
break;
|
||||
case ol.expr.ComparisonOp.GT:
|
||||
case ol.expr.ComparisonOp.LT:
|
||||
case ol.expr.ComparisonOp.GTE:
|
||||
case ol.expr.ComparisonOp.LTE:
|
||||
precedence = 4;
|
||||
break;
|
||||
case ol.expr.MathOp.ADD:
|
||||
case ol.expr.MathOp.SUBTRACT:
|
||||
precedence = 5;
|
||||
break;
|
||||
case ol.expr.MathOp.MULTIPLY:
|
||||
case ol.expr.MathOp.DIVIDE:
|
||||
case ol.expr.MathOp.MOD:
|
||||
precedence = 6;
|
||||
break;
|
||||
default:
|
||||
// punctuator is not a supported binary operator, that's fine
|
||||
break;
|
||||
}
|
||||
|
||||
return precedence;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Create a binary expression.
|
||||
*
|
||||
* @param {string} operator Operator.
|
||||
* @param {ol.expr.Expression} left Left expression.
|
||||
* @param {ol.expr.Expression} right Right expression.
|
||||
* @return {ol.expr.Expression} The expression.
|
||||
* @private
|
||||
*/
|
||||
ol.expr.Parser.prototype.createBinaryExpression_ = function(operator,
|
||||
left, right) {
|
||||
var expr;
|
||||
if (ol.expr.Comparison.isValidOp(operator)) {
|
||||
expr = new ol.expr.Comparison(
|
||||
/** @type {ol.expr.ComparisonOp.<string>} */ (operator),
|
||||
left, right);
|
||||
} else if (ol.expr.Logical.isValidOp(operator)) {
|
||||
expr = new ol.expr.Logical(
|
||||
/** @type {ol.expr.LogicalOp.<string>} */ (operator),
|
||||
left, right);
|
||||
} else if (ol.expr.Math.isValidOp(operator)) {
|
||||
expr = new ol.expr.Math(
|
||||
/** @type {ol.expr.MathOp.<string>} */ (operator),
|
||||
left, right);
|
||||
} else {
|
||||
throw new Error('Unsupported binary operator: ' + operator);
|
||||
}
|
||||
return expr;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Create a call expression.
|
||||
*
|
||||
* @param {ol.expr.Expression} callee Expression for function.
|
||||
* @param {Array.<ol.expr.Expression>} args Arguments array.
|
||||
* @return {ol.expr.Call} Call expression.
|
||||
* @private
|
||||
*/
|
||||
ol.expr.Parser.prototype.createCallExpression_ = function(callee, args) {
|
||||
return new ol.expr.Call(callee, args);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Create an identifier expression.
|
||||
*
|
||||
* @param {string} name Identifier name.
|
||||
* @return {ol.expr.Identifier} Identifier expression.
|
||||
* @private
|
||||
*/
|
||||
ol.expr.Parser.prototype.createIdentifier_ = function(name) {
|
||||
return new ol.expr.Identifier(name);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Create a literal expression.
|
||||
*
|
||||
* @param {string|number|boolean|null} value Literal value.
|
||||
* @return {ol.expr.Literal} The literal expression.
|
||||
* @private
|
||||
*/
|
||||
ol.expr.Parser.prototype.createLiteral_ = function(value) {
|
||||
return new ol.expr.Literal(value);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Create a member expression.
|
||||
*
|
||||
* // TODO: make exp {ol.expr.Member|ol.expr.Identifier}
|
||||
* @param {ol.expr.Expression} object Expression.
|
||||
* @param {ol.expr.Identifier} property Member name.
|
||||
* @return {ol.expr.Member} The member expression.
|
||||
* @private
|
||||
*/
|
||||
ol.expr.Parser.prototype.createMemberExpression_ = function(object,
|
||||
property) {
|
||||
return new ol.expr.Member(object, property);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Create a unary expression. The only true unary operator supported here is
|
||||
* "!". For +/-, we apply the operator to literal expressions and return
|
||||
* another literal.
|
||||
*
|
||||
* @param {ol.expr.Token} op Operator.
|
||||
* @param {ol.expr.Expression} argument Expression.
|
||||
* @return {ol.expr.Expression} The unary expression.
|
||||
* @private
|
||||
*/
|
||||
ol.expr.Parser.prototype.createUnaryExpression_ = function(op, argument) {
|
||||
goog.asserts.assert(op.value === '!' || op.value === '+' || op.value === '-');
|
||||
var expr;
|
||||
if (op.value === '!') {
|
||||
expr = new ol.expr.Not(argument);
|
||||
} else if (!(argument instanceof ol.expr.Literal)) {
|
||||
throw new ol.expr.UnexpectedToken(op);
|
||||
} else {
|
||||
// we've got +/- literal
|
||||
if (op.value === '+') {
|
||||
expr = this.createLiteral_(
|
||||
+ /** @type {number|string|boolean|null} */ (argument.evaluate()));
|
||||
} else {
|
||||
expr = this.createLiteral_(
|
||||
- /** @type {number|string|boolean|null} */ (argument.evaluate()));
|
||||
}
|
||||
}
|
||||
return expr;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Parse an expression.
|
||||
*
|
||||
* @param {string} source Expression source.
|
||||
* @return {ol.expr.Expression} Expression.
|
||||
*/
|
||||
ol.expr.Parser.prototype.parse = function(source) {
|
||||
var lexer = new ol.expr.Lexer(source);
|
||||
var expr = this.parseExpression_(lexer);
|
||||
var token = lexer.peek();
|
||||
if (token.type !== ol.expr.TokenType.EOF) {
|
||||
throw new ol.expr.UnexpectedToken(token);
|
||||
}
|
||||
return expr;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Parse call arguments
|
||||
* http://www.ecma-international.org/ecma-262/5.1/#sec-11.2.4
|
||||
*
|
||||
* @param {ol.expr.Lexer} lexer Lexer.
|
||||
* @return {Array.<ol.expr.Expression>} Arguments.
|
||||
* @private
|
||||
*/
|
||||
ol.expr.Parser.prototype.parseArguments_ = function(lexer) {
|
||||
var args = [];
|
||||
|
||||
lexer.expect('(');
|
||||
|
||||
if (!lexer.match(')')) {
|
||||
while (true) {
|
||||
args.push(this.parseBinaryExpression_(lexer));
|
||||
if (lexer.match(')')) {
|
||||
break;
|
||||
}
|
||||
lexer.expect(',');
|
||||
}
|
||||
}
|
||||
lexer.skip();
|
||||
|
||||
return args;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Parse a binary expression. Supported binary expressions:
|
||||
*
|
||||
* - Multiplicative Operators (`*`, `/`, `%`)
|
||||
* http://www.ecma-international.org/ecma-262/5.1/#sec-11.5
|
||||
|
||||
* - Additive Operators (`+`, `-`)
|
||||
* http://www.ecma-international.org/ecma-262/5.1/#sec-11.6
|
||||
*
|
||||
* - Relational Operators (`<`, `>`, `<=`, `>=`)
|
||||
* http://www.ecma-international.org/ecma-262/5.1/#sec-11.8
|
||||
*
|
||||
* - Equality Operators (`==`, `!=`, `===`, `!==`)
|
||||
* http://www.ecma-international.org/ecma-262/5.1/#sec-11.9
|
||||
*
|
||||
* - Binary Logical Operators (`&&`, `||`)
|
||||
* http://www.ecma-international.org/ecma-262/5.1/#sec-11.11
|
||||
*
|
||||
* @param {ol.expr.Lexer} lexer Lexer.
|
||||
* @return {ol.expr.Expression} Expression.
|
||||
* @private
|
||||
*/
|
||||
ol.expr.Parser.prototype.parseBinaryExpression_ = function(lexer) {
|
||||
var left = this.parseUnaryExpression_(lexer);
|
||||
|
||||
var operator = lexer.peek();
|
||||
var precedence = this.binaryPrecedence_(operator);
|
||||
if (precedence === 0) {
|
||||
// not a supported binary operator
|
||||
return left;
|
||||
}
|
||||
lexer.skip();
|
||||
|
||||
var right = this.parseUnaryExpression_(lexer);
|
||||
var stack = [left, operator, right];
|
||||
|
||||
precedence = this.binaryPrecedence_(lexer.peek());
|
||||
while (precedence > 0) {
|
||||
// TODO: cache operator precedence in stack
|
||||
while (stack.length > 2 &&
|
||||
(precedence <= this.binaryPrecedence_(stack[stack.length - 2]))) {
|
||||
right = stack.pop();
|
||||
operator = stack.pop();
|
||||
left = stack.pop();
|
||||
stack.push(this.createBinaryExpression_(operator.value, left, right));
|
||||
}
|
||||
stack.push(lexer.next());
|
||||
stack.push(this.parseUnaryExpression_(lexer));
|
||||
precedence = this.binaryPrecedence_(lexer.peek());
|
||||
}
|
||||
|
||||
var i = stack.length - 1;
|
||||
var expr = stack[i];
|
||||
while (i > 1) {
|
||||
expr = this.createBinaryExpression_(stack[i - 1].value, stack[i - 2], expr);
|
||||
i -= 2;
|
||||
}
|
||||
|
||||
return expr;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Parse a group expression.
|
||||
* http://www.ecma-international.org/ecma-262/5.1/#sec-11.1.6
|
||||
*
|
||||
* @param {ol.expr.Lexer} lexer Lexer.
|
||||
* @return {ol.expr.Expression} Expression.
|
||||
* @private
|
||||
*/
|
||||
ol.expr.Parser.prototype.parseGroupExpression_ = function(lexer) {
|
||||
lexer.expect('(');
|
||||
var expr = this.parseExpression_(lexer);
|
||||
lexer.expect(')');
|
||||
return expr;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Parse left-hand-side expression. Limited to Member Expressions
|
||||
* and Call Expressions.
|
||||
* http://www.ecma-international.org/ecma-262/5.1/#sec-11.2
|
||||
*
|
||||
* @param {ol.expr.Lexer} lexer Lexer.
|
||||
* @return {ol.expr.Expression} Expression.
|
||||
* @private
|
||||
*/
|
||||
ol.expr.Parser.prototype.parseLeftHandSideExpression_ = function(lexer) {
|
||||
var expr = this.parsePrimaryExpression_(lexer);
|
||||
var token = lexer.peek();
|
||||
if (token.value === '(') {
|
||||
// only allow calls on identifiers (e.g. `foo()` not `foo.bar()`)
|
||||
if (!(expr instanceof ol.expr.Identifier)) {
|
||||
// TODO: more helpful error messages for restricted syntax
|
||||
throw new ol.expr.UnexpectedToken(token);
|
||||
}
|
||||
var args = this.parseArguments_(lexer);
|
||||
expr = this.createCallExpression_(expr, args);
|
||||
} else {
|
||||
// TODO: throw if not Identifier
|
||||
while (token.value === '.') {
|
||||
var property = this.parseNonComputedMember_(lexer);
|
||||
expr = this.createMemberExpression_(expr, property);
|
||||
token = lexer.peek();
|
||||
}
|
||||
}
|
||||
return expr;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Parse non-computed member.
|
||||
* http://www.ecma-international.org/ecma-262/5.1/#sec-11.2
|
||||
*
|
||||
* @param {ol.expr.Lexer} lexer Lexer.
|
||||
* @return {ol.expr.Identifier} Expression.
|
||||
* @private
|
||||
*/
|
||||
ol.expr.Parser.prototype.parseNonComputedMember_ = function(lexer) {
|
||||
lexer.expect('.');
|
||||
|
||||
var token = lexer.next();
|
||||
if (token.type !== ol.expr.TokenType.IDENTIFIER &&
|
||||
token.type !== ol.expr.TokenType.KEYWORD &&
|
||||
token.type !== ol.expr.TokenType.BOOLEAN_LITERAL &&
|
||||
token.type !== ol.expr.TokenType.NULL_LITERAL) {
|
||||
throw new ol.expr.UnexpectedToken(token);
|
||||
}
|
||||
|
||||
return this.createIdentifier_(String(token.value));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Parse primary expression.
|
||||
* http://www.ecma-international.org/ecma-262/5.1/#sec-11.1
|
||||
*
|
||||
* @param {ol.expr.Lexer} lexer Lexer.
|
||||
* @return {ol.expr.Expression} Expression.
|
||||
* @private
|
||||
*/
|
||||
ol.expr.Parser.prototype.parsePrimaryExpression_ = function(lexer) {
|
||||
var token = lexer.peek();
|
||||
if (token.value === '(') {
|
||||
return this.parseGroupExpression_(lexer);
|
||||
}
|
||||
lexer.skip();
|
||||
var expr;
|
||||
var type = token.type;
|
||||
if (type === ol.expr.TokenType.IDENTIFIER) {
|
||||
expr = this.createIdentifier_(/** @type {string} */ (token.value));
|
||||
} else if (type === ol.expr.TokenType.STRING_LITERAL ||
|
||||
type === ol.expr.TokenType.NUMERIC_LITERAL) {
|
||||
// numeric and string literals are already the correct type
|
||||
expr = this.createLiteral_(token.value);
|
||||
} else if (type === ol.expr.TokenType.BOOLEAN_LITERAL) {
|
||||
// because booleans are valid member properties, tokens are still string
|
||||
expr = this.createLiteral_(token.value === 'true');
|
||||
} else if (type === ol.expr.TokenType.NULL_LITERAL) {
|
||||
expr = this.createLiteral_(null);
|
||||
} else {
|
||||
throw new ol.expr.UnexpectedToken(token);
|
||||
}
|
||||
return expr;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Parse expression with a unary operator. Limited to logical not operator.
|
||||
* http://www.ecma-international.org/ecma-262/5.1/#sec-11.4
|
||||
*
|
||||
* @param {ol.expr.Lexer} lexer Lexer.
|
||||
* @return {ol.expr.Expression} Expression.
|
||||
* @private
|
||||
*/
|
||||
ol.expr.Parser.prototype.parseUnaryExpression_ = function(lexer) {
|
||||
var expr;
|
||||
var operator = lexer.peek();
|
||||
if (operator.type !== ol.expr.TokenType.PUNCTUATOR) {
|
||||
expr = this.parseLeftHandSideExpression_(lexer);
|
||||
} else if (operator.value === '!' || operator.value === '-' ||
|
||||
operator.value === '+') {
|
||||
lexer.skip();
|
||||
expr = this.parseUnaryExpression_(lexer);
|
||||
expr = this.createUnaryExpression_(operator, expr);
|
||||
} else {
|
||||
expr = this.parseLeftHandSideExpression_(lexer);
|
||||
}
|
||||
return expr;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Parse an expression.
|
||||
*
|
||||
* @param {ol.expr.Lexer} lexer Lexer.
|
||||
* @return {ol.expr.Expression} Expression.
|
||||
* @private
|
||||
*/
|
||||
ol.expr.Parser.prototype.parseExpression_ = function(lexer) {
|
||||
return this.parseBinaryExpression_(lexer);
|
||||
};
|
||||
@@ -0,0 +1,16 @@
|
||||
@exportSymbol ol.extent.boundingExtent
|
||||
@exportSymbol ol.extent.containsCoordinate
|
||||
@exportSymbol ol.extent.containsExtent
|
||||
@exportSymbol ol.extent.equals
|
||||
@exportSymbol ol.extent.extend
|
||||
@exportSymbol ol.extent.getBottomLeft
|
||||
@exportSymbol ol.extent.getBottomRight
|
||||
@exportSymbol ol.extent.getCenter
|
||||
@exportSymbol ol.extent.getHeight
|
||||
@exportSymbol ol.extent.getSize
|
||||
@exportSymbol ol.extent.getTopLeft
|
||||
@exportSymbol ol.extent.getTopRight
|
||||
@exportSymbol ol.extent.getWidth
|
||||
@exportSymbol ol.extent.intersects
|
||||
@exportSymbol ol.extent.isEmpty
|
||||
@exportSymbol ol.extent.transform
|
||||
@@ -0,0 +1,345 @@
|
||||
goog.provide('ol.Extent');
|
||||
goog.provide('ol.extent');
|
||||
|
||||
goog.require('goog.asserts');
|
||||
goog.require('ol.Coordinate');
|
||||
goog.require('ol.Size');
|
||||
goog.require('ol.TransformFunction');
|
||||
|
||||
|
||||
/**
|
||||
* @typedef {Array.<number>}
|
||||
*/
|
||||
ol.Extent;
|
||||
|
||||
|
||||
/**
|
||||
* Builds an extent that includes all given coordinates.
|
||||
*
|
||||
* @param {Array.<ol.Coordinate>} coordinates Coordinates.
|
||||
* @return {ol.Extent} Bounding extent.
|
||||
*/
|
||||
ol.extent.boundingExtent = function(coordinates) {
|
||||
var extent = ol.extent.createEmpty();
|
||||
var n = coordinates.length;
|
||||
var i;
|
||||
for (i = 0; i < n; ++i) {
|
||||
ol.extent.extendCoordinate(extent, coordinates[i]);
|
||||
}
|
||||
return extent;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {Array.<number>} xs Xs.
|
||||
* @param {Array.<number>} ys Ys.
|
||||
* @param {ol.Extent=} opt_extent Destination extent.
|
||||
* @private
|
||||
* @return {ol.Extent} Extent.
|
||||
*/
|
||||
ol.extent.boundingExtentXYs_ = function(xs, ys, opt_extent) {
|
||||
goog.asserts.assert(xs.length > 0);
|
||||
goog.asserts.assert(ys.length > 0);
|
||||
var minX = Math.min.apply(null, xs);
|
||||
var maxX = Math.max.apply(null, xs);
|
||||
var minY = Math.min.apply(null, ys);
|
||||
var maxY = Math.max.apply(null, ys);
|
||||
return ol.extent.createOrUpdate(minX, maxX, minY, maxY, opt_extent);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Checks if the passed coordinate is contained or on the edge of the extent.
|
||||
*
|
||||
* @param {ol.Extent} extent Extent.
|
||||
* @param {ol.Coordinate} coordinate Coordinate.
|
||||
* @return {boolean} Contains.
|
||||
*/
|
||||
ol.extent.containsCoordinate = function(extent, coordinate) {
|
||||
return extent[0] <= coordinate[0] && coordinate[0] <= extent[1] &&
|
||||
extent[2] <= coordinate[1] && coordinate[1] <= extent[3];
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Checks if `extent2` is contained by or on the edge of `extent1`.
|
||||
*
|
||||
* @param {ol.Extent} extent1 Extent 1.
|
||||
* @param {ol.Extent} extent2 Extent 2.
|
||||
* @return {boolean} Contains.
|
||||
*/
|
||||
ol.extent.containsExtent = function(extent1, extent2) {
|
||||
return extent1[0] <= extent2[0] && extent2[1] <= extent1[1] &&
|
||||
extent1[2] <= extent2[2] && extent2[3] <= extent1[3];
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {ol.Extent} Empty extent.
|
||||
*/
|
||||
ol.extent.createEmpty = function() {
|
||||
return [Infinity, -Infinity, Infinity, -Infinity];
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {number} minX Minimum X.
|
||||
* @param {number} maxX Maximum X.
|
||||
* @param {number} minY Minimum Y.
|
||||
* @param {number} maxY Maximum Y.
|
||||
* @param {ol.Extent=} opt_extent Destination extent.
|
||||
* @return {ol.Extent} Extent.
|
||||
*/
|
||||
ol.extent.createOrUpdate = function(minX, maxX, minY, maxY, opt_extent) {
|
||||
if (goog.isDef(opt_extent)) {
|
||||
opt_extent[0] = minX;
|
||||
opt_extent[1] = maxX;
|
||||
opt_extent[2] = minY;
|
||||
opt_extent[3] = maxY;
|
||||
return opt_extent;
|
||||
} else {
|
||||
return [minX, maxX, minY, maxY];
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Empties extent in place.
|
||||
* @param {ol.Extent} extent Extent.
|
||||
* @return {ol.Extent} Extent.
|
||||
*/
|
||||
ol.extent.empty = function(extent) {
|
||||
extent[0] = extent[2] = Infinity;
|
||||
extent[1] = extent[3] = -Infinity;
|
||||
return extent;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {ol.Extent} extent1 Extent 1.
|
||||
* @param {ol.Extent} extent2 Extent 2.
|
||||
* @return {boolean} Equals.
|
||||
*/
|
||||
ol.extent.equals = function(extent1, extent2) {
|
||||
return extent1[0] == extent2[0] && extent1[1] == extent2[1] &&
|
||||
extent1[2] == extent2[2] && extent1[3] == extent2[3];
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {ol.Extent} extent1 Extent 1.
|
||||
* @param {ol.Extent} extent2 Extent 2.
|
||||
*/
|
||||
ol.extent.extend = function(extent1, extent2) {
|
||||
if (extent2[0] < extent1[0]) {
|
||||
extent1[0] = extent2[0];
|
||||
}
|
||||
if (extent2[1] > extent1[1]) {
|
||||
extent1[1] = extent2[1];
|
||||
}
|
||||
if (extent2[2] < extent1[2]) {
|
||||
extent1[2] = extent2[2];
|
||||
}
|
||||
if (extent2[3] > extent1[3]) {
|
||||
extent1[3] = extent2[3];
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {ol.Extent} extent Extent.
|
||||
* @param {ol.Coordinate} coordinate Coordinate.
|
||||
*/
|
||||
ol.extent.extendCoordinate = function(extent, coordinate) {
|
||||
if (coordinate[0] < extent[0]) {
|
||||
extent[0] = coordinate[0];
|
||||
}
|
||||
if (coordinate[0] > extent[1]) {
|
||||
extent[1] = coordinate[0];
|
||||
}
|
||||
if (coordinate[1] < extent[2]) {
|
||||
extent[2] = coordinate[1];
|
||||
}
|
||||
if (coordinate[1] > extent[3]) {
|
||||
extent[3] = coordinate[1];
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {ol.Extent} extent Extent.
|
||||
* @return {ol.Coordinate} Bottom left coordinate.
|
||||
*/
|
||||
ol.extent.getBottomLeft = function(extent) {
|
||||
return [extent[0], extent[2]];
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {ol.Extent} extent Extent.
|
||||
* @return {ol.Coordinate} Bottom right coordinate.
|
||||
*/
|
||||
ol.extent.getBottomRight = function(extent) {
|
||||
return [extent[1], extent[2]];
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {ol.Extent} extent Extent.
|
||||
* @return {ol.Coordinate} Center.
|
||||
*/
|
||||
ol.extent.getCenter = function(extent) {
|
||||
return [(extent[0] + extent[1]) / 2, (extent[2] + extent[3]) / 2];
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {ol.Coordinate} center Center.
|
||||
* @param {number} resolution Resolution.
|
||||
* @param {number} rotation Rotation.
|
||||
* @param {ol.Size} size Size.
|
||||
* @param {ol.Extent=} opt_extent Destination extent.
|
||||
* @return {ol.Extent} Extent.
|
||||
*/
|
||||
ol.extent.getForView2DAndSize =
|
||||
function(center, resolution, rotation, size, opt_extent) {
|
||||
var dx = resolution * size[0] / 2;
|
||||
var dy = resolution * size[1] / 2;
|
||||
var cosRotation = Math.cos(rotation);
|
||||
var sinRotation = Math.sin(rotation);
|
||||
/** @type {Array.<number>} */
|
||||
var xs = [-dx, -dx, dx, dx];
|
||||
/** @type {Array.<number>} */
|
||||
var ys = [-dy, dy, -dy, dy];
|
||||
var i, x, y;
|
||||
for (i = 0; i < 4; ++i) {
|
||||
x = xs[i];
|
||||
y = ys[i];
|
||||
xs[i] = center[0] + x * cosRotation - y * sinRotation;
|
||||
ys[i] = center[1] + x * sinRotation + y * cosRotation;
|
||||
}
|
||||
return ol.extent.boundingExtentXYs_(xs, ys, opt_extent);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {ol.Extent} extent Extent.
|
||||
* @return {number} Height.
|
||||
*/
|
||||
ol.extent.getHeight = function(extent) {
|
||||
return extent[3] - extent[2];
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {ol.Extent} extent Extent.
|
||||
* @return {ol.Size} Size.
|
||||
*/
|
||||
ol.extent.getSize = function(extent) {
|
||||
return [extent[1] - extent[0], extent[3] - extent[2]];
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {ol.Extent} extent Extent.
|
||||
* @return {ol.Coordinate} Top left coordinate.
|
||||
*/
|
||||
ol.extent.getTopLeft = function(extent) {
|
||||
return [extent[0], extent[3]];
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {ol.Extent} extent Extent.
|
||||
* @return {ol.Coordinate} Top right coordinate.
|
||||
*/
|
||||
ol.extent.getTopRight = function(extent) {
|
||||
return [extent[1], extent[3]];
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {ol.Extent} extent Extent.
|
||||
* @return {number} Width.
|
||||
*/
|
||||
ol.extent.getWidth = function(extent) {
|
||||
return extent[1] - extent[0];
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {ol.Extent} extent1 Extent 1.
|
||||
* @param {ol.Extent} extent2 Extent.
|
||||
* @return {boolean} Intersects.
|
||||
*/
|
||||
ol.extent.intersects = function(extent1, extent2) {
|
||||
return extent1[0] <= extent2[1] &&
|
||||
extent1[1] >= extent2[0] &&
|
||||
extent1[2] <= extent2[3] &&
|
||||
extent1[3] >= extent2[2];
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {ol.Extent} extent Extent.
|
||||
* @return {boolean} Is empty.
|
||||
*/
|
||||
ol.extent.isEmpty = function(extent) {
|
||||
return extent[1] < extent[0] || extent[3] < extent[2];
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {ol.Extent} extent Extent.
|
||||
* @param {ol.Coordinate} coordinate Coordinate.
|
||||
* @return {ol.Coordinate} Coordinate.
|
||||
*/
|
||||
ol.extent.normalize = function(extent, coordinate) {
|
||||
return [
|
||||
(coordinate[0] - extent[0]) / (extent[1] - extent[0]),
|
||||
(coordinate[1] - extent[2]) / (extent[3] - extent[2])
|
||||
];
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {ol.Extent} extent Extent.
|
||||
* @param {number} value Value.
|
||||
*/
|
||||
ol.extent.scaleFromCenter = function(extent, value) {
|
||||
var deltaX = ((extent[1] - extent[0]) / 2) * (value - 1);
|
||||
var deltaY = ((extent[3] - extent[2]) / 2) * (value - 1);
|
||||
extent[0] -= deltaX;
|
||||
extent[1] += deltaX;
|
||||
extent[2] -= deltaY;
|
||||
extent[3] += deltaY;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {ol.Extent} extent Extent.
|
||||
* @return {string} String.
|
||||
*/
|
||||
ol.extent.toString = function(extent) {
|
||||
return '(' + [extent[0], extent[1], extent[2], extent[3]].join(', ') + ')';
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {ol.Extent} extent Extent.
|
||||
* @param {ol.TransformFunction} transformFn Transform function.
|
||||
* @param {ol.Extent=} opt_extent Destination extent.
|
||||
* @return {ol.Extent} Extent.
|
||||
*/
|
||||
ol.extent.transform = function(extent, transformFn, opt_extent) {
|
||||
var coordinates = [
|
||||
extent[0], extent[2],
|
||||
extent[0], extent[3],
|
||||
extent[1], extent[2],
|
||||
extent[1], extent[3]
|
||||
];
|
||||
transformFn(coordinates, coordinates, 2);
|
||||
var xs = [coordinates[0], coordinates[2], coordinates[4], coordinates[6]];
|
||||
var ys = [coordinates[1], coordinates[3], coordinates[5], coordinates[7]];
|
||||
return ol.extent.boundingExtentXYs_(xs, ys, opt_extent);
|
||||
};
|
||||
@@ -0,0 +1,6 @@
|
||||
@exportSymbol ol.Feature
|
||||
@exportProperty ol.Feature.prototype.getAttributes
|
||||
@exportProperty ol.Feature.prototype.getFeatureId
|
||||
@exportProperty ol.Feature.prototype.getGeometry
|
||||
@exportProperty ol.Feature.prototype.set
|
||||
@exportProperty ol.Feature.prototype.setGeometry
|
||||
@@ -0,0 +1,152 @@
|
||||
goog.provide('ol.Feature');
|
||||
|
||||
goog.require('ol.Object');
|
||||
goog.require('ol.geom.Geometry');
|
||||
goog.require('ol.layer.VectorLayerRenderIntent');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Create a new feature. A feature is the base entity for vectors and has
|
||||
* attributes, including normally a geometry attribute.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* var feature = new ol.Feature({'foo': 'bar'});
|
||||
* feature.setGeometry(new ol.geom.Point([100, 500]));
|
||||
*
|
||||
* @constructor
|
||||
* @extends {ol.Object}
|
||||
* @param {Object.<string, *>=} opt_values Attributes.
|
||||
*/
|
||||
ol.Feature = function(opt_values) {
|
||||
|
||||
goog.base(this, opt_values);
|
||||
|
||||
/**
|
||||
* @type {string|undefined}
|
||||
* @private
|
||||
*/
|
||||
this.featureId_;
|
||||
|
||||
/**
|
||||
* @type {string|undefined}
|
||||
* @private
|
||||
*/
|
||||
this.geometryName_;
|
||||
|
||||
/**
|
||||
* The render intent for this feature.
|
||||
* @type {ol.layer.VectorLayerRenderIntent|string}
|
||||
*/
|
||||
this.renderIntent = ol.layer.VectorLayerRenderIntent.DEFAULT;
|
||||
|
||||
/**
|
||||
* @type {Array.<ol.style.Symbolizer>}
|
||||
* @private
|
||||
*/
|
||||
this.symbolizers_ = null;
|
||||
|
||||
};
|
||||
goog.inherits(ol.Feature, ol.Object);
|
||||
|
||||
|
||||
/**
|
||||
* Gets a copy of the attributes of this feature.
|
||||
* @return {Object.<string, *>} Attributes object.
|
||||
*/
|
||||
ol.Feature.prototype.getAttributes = function() {
|
||||
var keys = this.getKeys(),
|
||||
len = keys.length,
|
||||
attributes = {},
|
||||
i, key;
|
||||
for (i = 0; i < len; ++ i) {
|
||||
key = keys[i];
|
||||
attributes[key] = this.get(key);
|
||||
}
|
||||
return attributes;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns the feature's commonly used identifier. This identifier is usually
|
||||
* the unique id in the source store.
|
||||
*
|
||||
* @return {string|undefined} The feature's identifier.
|
||||
*/
|
||||
ol.Feature.prototype.getFeatureId = function() {
|
||||
return this.featureId_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get the geometry associated with this feature.
|
||||
* @return {ol.geom.Geometry} The geometry (or null if none).
|
||||
*/
|
||||
ol.Feature.prototype.getGeometry = function() {
|
||||
return goog.isDef(this.geometryName_) ?
|
||||
/** @type {ol.geom.Geometry} */ (this.get(this.geometryName_)) :
|
||||
null;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get any symbolizers set directly on the feature.
|
||||
* @return {Array.<ol.style.Symbolizer>} Symbolizers (or null if none).
|
||||
*/
|
||||
ol.Feature.prototype.getSymbolizers = function() {
|
||||
return this.symbolizers_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @param {string} key Key.
|
||||
* @param {*} value Value.
|
||||
*/
|
||||
ol.Feature.prototype.set = function(key, value) {
|
||||
if (!goog.isDef(this.geometryName_) && (value instanceof ol.geom.Geometry)) {
|
||||
this.geometryName_ = key;
|
||||
}
|
||||
goog.base(this, 'set', key, value);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Set the feature's commonly used identifier. This identifier is usually the
|
||||
* unique id in the source store.
|
||||
*
|
||||
* @param {string|undefined} featureId The feature's identifier.
|
||||
*/
|
||||
ol.Feature.prototype.setFeatureId = function(featureId) {
|
||||
this.featureId_ = featureId;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Set the geometry to be associated with this feature after its creation.
|
||||
* @param {ol.geom.Geometry} geometry The geometry.
|
||||
*/
|
||||
ol.Feature.prototype.setGeometry = function(geometry) {
|
||||
if (!goog.isDef(this.geometryName_)) {
|
||||
this.geometryName_ = ol.Feature.DEFAULT_GEOMETRY;
|
||||
}
|
||||
this.set(this.geometryName_, geometry);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Set the symbolizers to be used for this feature.
|
||||
* @param {Array.<ol.style.Symbolizer>} symbolizers Symbolizers for this
|
||||
* feature. If set, these take precedence over layer style.
|
||||
*/
|
||||
ol.Feature.prototype.setSymbolizers = function(symbolizers) {
|
||||
this.symbolizers_ = symbolizers;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @const
|
||||
* @type {string}
|
||||
*/
|
||||
ol.Feature.DEFAULT_GEOMETRY = 'geometry';
|
||||
@@ -0,0 +1,51 @@
|
||||
// FIXME add view3DState
|
||||
// FIXME factor out common code between usedTiles and wantedTiles
|
||||
|
||||
goog.provide('ol.FrameState');
|
||||
goog.provide('ol.PostRenderFunction');
|
||||
goog.provide('ol.PreRenderFunction');
|
||||
|
||||
goog.require('goog.vec.Mat4');
|
||||
goog.require('ol.Attribution');
|
||||
goog.require('ol.Extent');
|
||||
goog.require('ol.Size');
|
||||
goog.require('ol.TileQueue');
|
||||
goog.require('ol.TileRange');
|
||||
goog.require('ol.View2DState');
|
||||
goog.require('ol.layer.Layer');
|
||||
goog.require('ol.layer.LayerState');
|
||||
|
||||
|
||||
/**
|
||||
* @typedef {{animate: boolean,
|
||||
* attributions: Object.<string, ol.Attribution>,
|
||||
* coordinateToPixelMatrix: goog.vec.Mat4.Number,
|
||||
* extent: (null|ol.Extent),
|
||||
* focus: ol.Coordinate,
|
||||
* index: number,
|
||||
* layersArray: Array.<ol.layer.Layer>,
|
||||
* layerStates: Object.<number, ol.layer.LayerState>,
|
||||
* logos: Object.<string, boolean>,
|
||||
* pixelToCoordinateMatrix: goog.vec.Mat4.Number,
|
||||
* postRenderFunctions: Array.<ol.PostRenderFunction>,
|
||||
* size: ol.Size,
|
||||
* tileQueue: ol.TileQueue,
|
||||
* time: number,
|
||||
* usedTiles: Object.<string, Object.<string, ol.TileRange>>,
|
||||
* view2DState: ol.View2DState,
|
||||
* viewHints: Array.<number>,
|
||||
* wantedTiles: Object.<string, Object.<string, boolean>>}}
|
||||
*/
|
||||
ol.FrameState;
|
||||
|
||||
|
||||
/**
|
||||
* @typedef {function(ol.Map, ?ol.FrameState): boolean}
|
||||
*/
|
||||
ol.PostRenderFunction;
|
||||
|
||||
|
||||
/**
|
||||
* @typedef {function(ol.Map, ?ol.FrameState): boolean}
|
||||
*/
|
||||
ol.PreRenderFunction;
|
||||
@@ -0,0 +1,2 @@
|
||||
@exportClass ol.Geolocation ol.GeolocationOptions
|
||||
@exportSymbol ol.Geolocation.SUPPORTED
|
||||
@@ -0,0 +1,351 @@
|
||||
// FIXME handle geolocation not supported
|
||||
|
||||
goog.provide('ol.Geolocation');
|
||||
goog.provide('ol.Geolocation.SUPPORTED');
|
||||
goog.provide('ol.GeolocationProperty');
|
||||
|
||||
goog.require('goog.events');
|
||||
goog.require('goog.events.EventType');
|
||||
goog.require('goog.math');
|
||||
goog.require('ol.Coordinate');
|
||||
goog.require('ol.Object');
|
||||
goog.require('ol.Projection');
|
||||
goog.require('ol.proj');
|
||||
|
||||
|
||||
/**
|
||||
* @enum {string}
|
||||
*/
|
||||
ol.GeolocationProperty = {
|
||||
ACCURACY: 'accuracy',
|
||||
ALTITUDE: 'altitude',
|
||||
ALTITUDE_ACCURACY: 'altitudeAccuracy',
|
||||
HEADING: 'heading',
|
||||
POSITION: 'position',
|
||||
PROJECTION: 'projection',
|
||||
SPEED: 'speed',
|
||||
TRACKING: 'tracking',
|
||||
TRACKING_OPTIONS: 'trackingOptions'
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Helper class for providing HTML5 Geolocation capabilities.
|
||||
* The [Geolocation API](http://dev.w3.org/geo/api/spec-source.html)
|
||||
* is used to locate a user's position.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* var geolocation = new ol.Geolocation();
|
||||
* // take the projection to use from the map's view
|
||||
* geolocation.bindTo('projection', map.getView());
|
||||
* // listen to changes in position
|
||||
* geolocation.on('change:position', function(evt) {
|
||||
* window.console.log(geolocation.getPosition());
|
||||
* });
|
||||
*
|
||||
* @constructor
|
||||
* @extends {ol.Object}
|
||||
* @param {ol.GeolocationOptions=} opt_options Options.
|
||||
*/
|
||||
ol.Geolocation = function(opt_options) {
|
||||
|
||||
goog.base(this);
|
||||
|
||||
var options = goog.isDef(opt_options) ? opt_options : {};
|
||||
|
||||
/**
|
||||
* The unprojected (EPSG:4326) device position.
|
||||
* @private
|
||||
* @type {ol.Coordinate}
|
||||
*/
|
||||
this.position_ = null;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {ol.TransformFunction}
|
||||
*/
|
||||
this.transform_ = ol.proj.identityTransform;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {number|undefined}
|
||||
*/
|
||||
this.watchId_ = undefined;
|
||||
|
||||
goog.events.listen(
|
||||
this, ol.Object.getChangeEventType(ol.GeolocationProperty.PROJECTION),
|
||||
this.handleProjectionChanged_, false, this);
|
||||
goog.events.listen(
|
||||
this, ol.Object.getChangeEventType(ol.GeolocationProperty.TRACKING),
|
||||
this.handleTrackingChanged_, false, this);
|
||||
|
||||
if (goog.isDef(options.projection)) {
|
||||
this.setProjection(ol.proj.get(options.projection));
|
||||
}
|
||||
if (goog.isDef(options.trackingOptions)) {
|
||||
this.setTrackingOptions(options.trackingOptions);
|
||||
}
|
||||
|
||||
this.setTracking(goog.isDef(options.tracking) ? options.tracking : false);
|
||||
|
||||
};
|
||||
goog.inherits(ol.Geolocation, ol.Object);
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
ol.Geolocation.prototype.disposeInternal = function() {
|
||||
this.setTracking(false);
|
||||
goog.base(this, 'disposeInternal');
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
ol.Geolocation.prototype.handleProjectionChanged_ = function() {
|
||||
var projection = this.getProjection();
|
||||
if (goog.isDefAndNotNull(projection)) {
|
||||
this.transform_ = ol.proj.getTransformFromProjections(
|
||||
ol.proj.get('EPSG:4326'), projection);
|
||||
if (!goog.isNull(this.position_)) {
|
||||
this.set(
|
||||
ol.GeolocationProperty.POSITION, this.transform_(this.position_));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
ol.Geolocation.prototype.handleTrackingChanged_ = function() {
|
||||
if (ol.Geolocation.SUPPORTED) {
|
||||
var tracking = this.getTracking();
|
||||
if (tracking && !goog.isDef(this.watchId_)) {
|
||||
this.watchId_ = goog.global.navigator.geolocation.watchPosition(
|
||||
goog.bind(this.positionChange_, this),
|
||||
goog.bind(this.positionError_, this),
|
||||
this.getTrackingOptions());
|
||||
} else if (!tracking && goog.isDef(this.watchId_)) {
|
||||
goog.global.navigator.geolocation.clearWatch(this.watchId_);
|
||||
this.watchId_ = undefined;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Is HTML5 geolocation supported in the current browser?
|
||||
* @const
|
||||
* @type {boolean}
|
||||
*/
|
||||
ol.Geolocation.SUPPORTED = 'geolocation' in goog.global.navigator;
|
||||
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {GeolocationPosition} position position event.
|
||||
*/
|
||||
ol.Geolocation.prototype.positionChange_ = function(position) {
|
||||
var coords = position.coords;
|
||||
this.set(ol.GeolocationProperty.ACCURACY, coords.accuracy);
|
||||
this.set(ol.GeolocationProperty.ALTITUDE,
|
||||
goog.isNull(coords.altitude) ? undefined : coords.altitude);
|
||||
this.set(ol.GeolocationProperty.ALTITUDE_ACCURACY,
|
||||
goog.isNull(coords.altitudeAccuracy) ?
|
||||
undefined : coords.altitudeAccuracy);
|
||||
this.set(ol.GeolocationProperty.HEADING, goog.isNull(coords.heading) ?
|
||||
undefined : goog.math.toRadians(coords.heading));
|
||||
if (goog.isNull(this.position_)) {
|
||||
this.position_ = [coords.longitude, coords.latitude];
|
||||
} else {
|
||||
this.position_[0] = coords.longitude;
|
||||
this.position_[1] = coords.latitude;
|
||||
}
|
||||
this.set(ol.GeolocationProperty.POSITION, this.transform_(this.position_));
|
||||
this.set(ol.GeolocationProperty.SPEED,
|
||||
goog.isNull(coords.speed) ? undefined : coords.speed);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {GeolocationPositionError} error error object.
|
||||
*/
|
||||
ol.Geolocation.prototype.positionError_ = function(error) {
|
||||
error.type = goog.events.EventType.ERROR;
|
||||
this.dispatchEvent(error);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get the accuracy of the position in meters.
|
||||
* @return {number|undefined} accuracy in meters.
|
||||
*/
|
||||
ol.Geolocation.prototype.getAccuracy = function() {
|
||||
return /** @type {number|undefined} */ (
|
||||
this.get(ol.GeolocationProperty.ACCURACY));
|
||||
};
|
||||
goog.exportProperty(
|
||||
ol.Geolocation.prototype,
|
||||
'getAccuracy',
|
||||
ol.Geolocation.prototype.getAccuracy);
|
||||
|
||||
|
||||
/**
|
||||
* Get the altitude associated with the position.
|
||||
* @return {number|undefined} The altitude in meters above the mean sea level.
|
||||
*/
|
||||
ol.Geolocation.prototype.getAltitude = function() {
|
||||
return /** @type {number|undefined} */ (
|
||||
this.get(ol.GeolocationProperty.ALTITUDE));
|
||||
};
|
||||
goog.exportProperty(
|
||||
ol.Geolocation.prototype,
|
||||
'getAltitude',
|
||||
ol.Geolocation.prototype.getAltitude);
|
||||
|
||||
|
||||
/**
|
||||
* Get the altitude accuracy of the position.
|
||||
* @return {number|undefined} Altitude accuracy.
|
||||
*/
|
||||
ol.Geolocation.prototype.getAltitudeAccuracy = function() {
|
||||
return /** @type {number|undefined} */ (
|
||||
this.get(ol.GeolocationProperty.ALTITUDE_ACCURACY));
|
||||
};
|
||||
goog.exportProperty(
|
||||
ol.Geolocation.prototype,
|
||||
'getAltitudeAccuracy',
|
||||
ol.Geolocation.prototype.getAltitudeAccuracy);
|
||||
|
||||
|
||||
/**
|
||||
* Get the heading as radians clockwise from North.
|
||||
* @return {number|undefined} Heading.
|
||||
*/
|
||||
ol.Geolocation.prototype.getHeading = function() {
|
||||
return /** @type {number|undefined} */ (
|
||||
this.get(ol.GeolocationProperty.HEADING));
|
||||
};
|
||||
goog.exportProperty(
|
||||
ol.Geolocation.prototype,
|
||||
'getHeading',
|
||||
ol.Geolocation.prototype.getHeading);
|
||||
|
||||
|
||||
/**
|
||||
* Get the position of the device.
|
||||
* @return {ol.Coordinate|undefined} position.
|
||||
*/
|
||||
ol.Geolocation.prototype.getPosition = function() {
|
||||
return /** @type {ol.Coordinate|undefined} */ (
|
||||
this.get(ol.GeolocationProperty.POSITION));
|
||||
};
|
||||
goog.exportProperty(
|
||||
ol.Geolocation.prototype,
|
||||
'getPosition',
|
||||
ol.Geolocation.prototype.getPosition);
|
||||
|
||||
|
||||
/**
|
||||
* Get the projection associated with the position.
|
||||
* @return {ol.Projection|undefined} projection.
|
||||
*/
|
||||
ol.Geolocation.prototype.getProjection = function() {
|
||||
return /** @type {ol.Projection|undefined} */ (
|
||||
this.get(ol.GeolocationProperty.PROJECTION));
|
||||
};
|
||||
goog.exportProperty(
|
||||
ol.Geolocation.prototype,
|
||||
'getProjection',
|
||||
ol.Geolocation.prototype.getProjection);
|
||||
|
||||
|
||||
/**
|
||||
* Get the speed in meters per second.
|
||||
* @return {number|undefined} Speed.
|
||||
*/
|
||||
ol.Geolocation.prototype.getSpeed = function() {
|
||||
return /** @type {number|undefined} */ (
|
||||
this.get(ol.GeolocationProperty.SPEED));
|
||||
};
|
||||
goog.exportProperty(
|
||||
ol.Geolocation.prototype,
|
||||
'getSpeed',
|
||||
ol.Geolocation.prototype.getSpeed);
|
||||
|
||||
|
||||
/**
|
||||
* Are we tracking the user's position?
|
||||
* @return {boolean} tracking.
|
||||
*/
|
||||
ol.Geolocation.prototype.getTracking = function() {
|
||||
return /** @type {boolean} */ (
|
||||
this.get(ol.GeolocationProperty.TRACKING));
|
||||
};
|
||||
goog.exportProperty(
|
||||
ol.Geolocation.prototype,
|
||||
'getTracking',
|
||||
ol.Geolocation.prototype.getTracking);
|
||||
|
||||
|
||||
/**
|
||||
* Get the tracking options.
|
||||
* @see http://www.w3.org/TR/geolocation-API/#position-options
|
||||
* @return {GeolocationPositionOptions|undefined} HTML 5 Gelocation
|
||||
* tracking options.
|
||||
*/
|
||||
ol.Geolocation.prototype.getTrackingOptions = function() {
|
||||
return /** @type {GeolocationPositionOptions|undefined} */ (
|
||||
this.get(ol.GeolocationProperty.TRACKING_OPTIONS));
|
||||
};
|
||||
goog.exportProperty(
|
||||
ol.Geolocation.prototype,
|
||||
'getTrackingOptions',
|
||||
ol.Geolocation.prototype.getTrackingOptions);
|
||||
|
||||
|
||||
/**
|
||||
* Set the projection to use for transforming the coordinates.
|
||||
* @param {ol.Projection} projection Projection.
|
||||
*/
|
||||
ol.Geolocation.prototype.setProjection = function(projection) {
|
||||
this.set(ol.GeolocationProperty.PROJECTION, projection);
|
||||
};
|
||||
goog.exportProperty(
|
||||
ol.Geolocation.prototype,
|
||||
'setProjection',
|
||||
ol.Geolocation.prototype.setProjection);
|
||||
|
||||
|
||||
/**
|
||||
* Enable/disable tracking.
|
||||
* @param {boolean} tracking Enable or disable tracking.
|
||||
*/
|
||||
ol.Geolocation.prototype.setTracking = function(tracking) {
|
||||
this.set(ol.GeolocationProperty.TRACKING, tracking);
|
||||
};
|
||||
goog.exportProperty(
|
||||
ol.Geolocation.prototype,
|
||||
'setTracking',
|
||||
ol.Geolocation.prototype.setTracking);
|
||||
|
||||
|
||||
/**
|
||||
* Set the tracking options.
|
||||
* @see http://www.w3.org/TR/geolocation-API/#position-options
|
||||
* @param {GeolocationPositionOptions} options HTML 5 Geolocation
|
||||
* tracking options.
|
||||
*/
|
||||
ol.Geolocation.prototype.setTrackingOptions = function(options) {
|
||||
this.set(ol.GeolocationProperty.TRACKING_OPTIONS, options);
|
||||
};
|
||||
goog.exportProperty(
|
||||
ol.Geolocation.prototype,
|
||||
'setTrackingOptions',
|
||||
ol.Geolocation.prototype.setTrackingOptions);
|
||||
@@ -0,0 +1,29 @@
|
||||
@exportSymbol ol.geom.GeometryType
|
||||
@exportProperty ol.geom.GeometryType.POINT
|
||||
@exportProperty ol.geom.GeometryType.LINEARRING
|
||||
@exportProperty ol.geom.GeometryType.LINESTRING
|
||||
@exportProperty ol.geom.GeometryType.POLYGON
|
||||
@exportProperty ol.geom.GeometryType.MULTIPOINT
|
||||
@exportProperty ol.geom.GeometryType.MULTILINESTRING
|
||||
@exportProperty ol.geom.GeometryType.MULTIPOLYGON
|
||||
@exportProperty ol.geom.GeometryType.GEOMETRYCOLLECTION
|
||||
|
||||
@exportSymbol ol.geom.Geometry
|
||||
|
||||
@exportSymbol ol.geom.Point
|
||||
@exportProperty ol.geom.Point.prototype.getCoordinates
|
||||
|
||||
@exportSymbol ol.geom.LineString
|
||||
@exportProperty ol.geom.LineString.prototype.getCoordinates
|
||||
|
||||
@exportSymbol ol.geom.Polygon
|
||||
@exportProperty ol.geom.Polygon.prototype.getCoordinates
|
||||
|
||||
@exportSymbol ol.geom.MultiPoint
|
||||
@exportProperty ol.geom.MultiPoint.prototype.getCoordinates
|
||||
|
||||
@exportSymbol ol.geom.MultiLineString
|
||||
@exportProperty ol.geom.MultiLineString.prototype.getCoordinates
|
||||
|
||||
@exportSymbol ol.geom.MultiPolygon
|
||||
@exportProperty ol.geom.MultiPolygon.prototype.getCoordinates
|
||||
@@ -0,0 +1,3 @@
|
||||
/**
|
||||
* @namespace ol.geom
|
||||
*/
|
||||
@@ -0,0 +1,86 @@
|
||||
goog.provide('ol.geom.AbstractCollection');
|
||||
|
||||
goog.require('ol.geom.Geometry');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* A collection of geometries. This constructor is not to be used directly.
|
||||
*
|
||||
* @constructor
|
||||
* @extends {ol.geom.Geometry}
|
||||
*/
|
||||
ol.geom.AbstractCollection = function() {
|
||||
goog.base(this);
|
||||
|
||||
/**
|
||||
* @type {number}
|
||||
*/
|
||||
this.dimension;
|
||||
|
||||
/**
|
||||
* @type {Array.<ol.geom.Geometry>}
|
||||
*/
|
||||
this.components = null;
|
||||
|
||||
/**
|
||||
* @type {ol.Extent}
|
||||
* @protected
|
||||
*/
|
||||
this.bounds = null;
|
||||
|
||||
};
|
||||
goog.inherits(ol.geom.AbstractCollection, ol.geom.Geometry);
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
ol.geom.AbstractCollection.prototype.getBounds = function() {
|
||||
if (goog.isNull(this.bounds)) {
|
||||
var minX,
|
||||
minY = minX = Infinity,
|
||||
maxX,
|
||||
maxY = maxX = -Infinity,
|
||||
components = this.components,
|
||||
len = components.length,
|
||||
bounds, i;
|
||||
|
||||
for (i = 0; i < len; ++i) {
|
||||
bounds = components[i].getBounds();
|
||||
minX = Math.min(bounds[0], minX);
|
||||
maxX = Math.max(bounds[1], maxX);
|
||||
minY = Math.min(bounds[2], minY);
|
||||
maxY = Math.max(bounds[3], maxY);
|
||||
}
|
||||
this.bounds = [minX, maxX, minY, maxY];
|
||||
}
|
||||
return this.bounds;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
ol.geom.AbstractCollection.prototype.getCoordinates = function() {
|
||||
var count = this.components.length;
|
||||
var coordinates = new Array(count);
|
||||
for (var i = 0; i < count; ++i) {
|
||||
coordinates[i] = this.components[i].getCoordinates();
|
||||
}
|
||||
return coordinates;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
ol.geom.AbstractCollection.prototype.getType = goog.abstractMethod;
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
ol.geom.AbstractCollection.prototype.invalidateBounds = function() {
|
||||
this.bounds = null;
|
||||
};
|
||||
@@ -0,0 +1,15 @@
|
||||
goog.provide('ol.geom');
|
||||
|
||||
goog.require('ol.coordinate');
|
||||
|
||||
|
||||
/**
|
||||
* Calculate the squared distance from a point to a line segment.
|
||||
*
|
||||
* @param {ol.Coordinate} coordinate Coordinate of the point.
|
||||
* @param {Array.<ol.Coordinate>} segment Line segment (2 coordinates).
|
||||
* @return {number} Squared distance from the point to the line segment.
|
||||
*/
|
||||
ol.geom.squaredDistanceToSegment = function(coordinate, segment) {
|
||||
return ol.coordinate.closestOnSegment(coordinate, segment)[2];
|
||||
};
|
||||
@@ -0,0 +1,91 @@
|
||||
goog.provide('ol.geom.Geometry');
|
||||
goog.provide('ol.geom.GeometryType');
|
||||
|
||||
goog.require('ol.Extent');
|
||||
goog.require('ol.geom.SharedVertices');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
*/
|
||||
ol.geom.Geometry = function() {
|
||||
|
||||
/**
|
||||
* @type {ol.geom.SharedVertices}
|
||||
* @protected
|
||||
*/
|
||||
this.vertices = null;
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* The dimension of this geometry (2 or 3).
|
||||
* @type {number}
|
||||
*/
|
||||
ol.geom.Geometry.prototype.dimension;
|
||||
|
||||
|
||||
/**
|
||||
* Create a clone of this geometry. The clone will not be represented in any
|
||||
* shared structure.
|
||||
* @return {ol.geom.Geometry} The cloned geometry.
|
||||
*/
|
||||
ol.geom.Geometry.prototype.clone = function() {
|
||||
var clone = new this.constructor(this.getCoordinates());
|
||||
clone.dimension = this.dimension;
|
||||
return clone;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get the rectangular 2D envelope for this geoemtry.
|
||||
* @return {ol.Extent} The bounding rectangular envelope.
|
||||
*/
|
||||
ol.geom.Geometry.prototype.getBounds = goog.abstractMethod;
|
||||
|
||||
|
||||
/**
|
||||
* @return {Array} The GeoJSON style coordinates array for the geometry.
|
||||
*/
|
||||
ol.geom.Geometry.prototype.getCoordinates = goog.abstractMethod;
|
||||
|
||||
|
||||
/**
|
||||
* Get the shared vertices for this geometry.
|
||||
* @return {ol.geom.SharedVertices} The shared vertices.
|
||||
*/
|
||||
ol.geom.Geometry.prototype.getSharedVertices = function() {
|
||||
return this.vertices;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get the geometry type.
|
||||
* @return {ol.geom.GeometryType} The geometry type.
|
||||
*/
|
||||
ol.geom.Geometry.prototype.getType = goog.abstractMethod;
|
||||
|
||||
|
||||
/**
|
||||
* Invalidates the rectangular 2D envelope for this geoemtry.
|
||||
*/
|
||||
ol.geom.Geometry.prototype.invalidateBounds = goog.abstractMethod;
|
||||
|
||||
|
||||
/**
|
||||
* Geometry types.
|
||||
*
|
||||
* @enum {string}
|
||||
*/
|
||||
ol.geom.GeometryType = {
|
||||
POINT: 'point',
|
||||
LINESTRING: 'linestring',
|
||||
LINEARRING: 'linearring',
|
||||
POLYGON: 'polygon',
|
||||
MULTIPOINT: 'multipoint',
|
||||
MULTILINESTRING: 'multilinestring',
|
||||
MULTIPOLYGON: 'multipolygon',
|
||||
GEOMETRYCOLLECTION: 'geometrycollection'
|
||||
};
|
||||
@@ -0,0 +1,49 @@
|
||||
goog.provide('ol.geom.GeometryCollection');
|
||||
|
||||
goog.require('goog.asserts');
|
||||
goog.require('ol.geom.AbstractCollection');
|
||||
goog.require('ol.geom.Geometry');
|
||||
goog.require('ol.geom.GeometryType');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* A mixed collection of geometries. Used one of the fixed type multi-part
|
||||
* constructors for collections of the same type.
|
||||
*
|
||||
* @constructor
|
||||
* @extends {ol.geom.AbstractCollection}
|
||||
* @param {Array.<ol.geom.Geometry>} geometries Array of geometries.
|
||||
*/
|
||||
ol.geom.GeometryCollection = function(geometries) {
|
||||
goog.base(this);
|
||||
|
||||
/**
|
||||
* @type {Array.<ol.geom.Geometry>}
|
||||
*/
|
||||
this.components = geometries;
|
||||
|
||||
var dimension = 0;
|
||||
for (var i = 0, ii = geometries.length; i < ii; ++i) {
|
||||
if (goog.isDef(dimension)) {
|
||||
dimension = geometries[i].dimension;
|
||||
} else {
|
||||
goog.asserts.assert(dimension == geometries[i].dimension);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @type {number}
|
||||
*/
|
||||
this.dimension = dimension;
|
||||
|
||||
};
|
||||
goog.inherits(ol.geom.GeometryCollection, ol.geom.AbstractCollection);
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
ol.geom.GeometryCollection.prototype.getType = function() {
|
||||
return ol.geom.GeometryType.GEOMETRYCOLLECTION;
|
||||
};
|
||||
@@ -0,0 +1,101 @@
|
||||
goog.provide('ol.geom.LinearRing');
|
||||
|
||||
goog.require('ol.CoordinateArray');
|
||||
goog.require('ol.geom.GeometryType');
|
||||
goog.require('ol.geom.LineString');
|
||||
goog.require('ol.geom.SharedVertices');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
* @extends {ol.geom.LineString}
|
||||
* @param {ol.CoordinateArray} coordinates Vertex array (e.g.
|
||||
* [[x0, y0], [x1, y1]]).
|
||||
* @param {ol.geom.SharedVertices=} opt_shared Shared vertices.
|
||||
*/
|
||||
ol.geom.LinearRing = function(coordinates, opt_shared) {
|
||||
goog.base(this, coordinates, opt_shared);
|
||||
|
||||
/**
|
||||
* We're intentionally not enforcing that rings be closed right now. This
|
||||
* will allow proper rendering of data from tiled vector sources that leave
|
||||
* open rings.
|
||||
*/
|
||||
|
||||
};
|
||||
goog.inherits(ol.geom.LinearRing, ol.geom.LineString);
|
||||
|
||||
|
||||
/**
|
||||
* Determine if a vertex array representing a linear ring is in clockwise
|
||||
* order.
|
||||
*
|
||||
* This method comes from Green's Theorem and was mentioned in an answer to a
|
||||
* a Stack Overflow question (http://tinyurl.com/clockwise-method).
|
||||
*
|
||||
* Note that calculating the cross product for each pair of edges could be
|
||||
* avoided by first finding the lowest, rightmost vertex. See OGR's
|
||||
* implementation for an example of this.
|
||||
* https://github.com/OSGeo/gdal/blob/trunk/gdal/ogr/ogrlinearring.cpp
|
||||
*
|
||||
* @param {ol.CoordinateArray} coordinates Linear ring coordinates.
|
||||
* @return {boolean} The coordinates are in clockwise order.
|
||||
*/
|
||||
ol.geom.LinearRing.isClockwise = function(coordinates) {
|
||||
var length = coordinates.length;
|
||||
var edge = 0;
|
||||
|
||||
var last = coordinates[length - 1];
|
||||
var x1 = last[0];
|
||||
var y1 = last[1];
|
||||
|
||||
var x2, y2, coord;
|
||||
for (var i = 0; i < length; ++i) {
|
||||
coord = coordinates[i];
|
||||
x2 = coord[0];
|
||||
y2 = coord[1];
|
||||
edge += (x2 - x1) * (y2 + y1);
|
||||
x1 = x2;
|
||||
y1 = y2;
|
||||
}
|
||||
return edge > 0;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
ol.geom.LinearRing.prototype.getType = function() {
|
||||
return ol.geom.GeometryType.LINEARRING;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Check whether a given coordinate is inside this ring. Note that this is a
|
||||
* fast and simple check - points on an edge or vertex of the ring are either
|
||||
* classified inside or outside.
|
||||
*
|
||||
* @param {ol.Coordinate} coordinate Coordinate.
|
||||
* @return {boolean} Whether the coordinate is inside the ring.
|
||||
*/
|
||||
ol.geom.LinearRing.prototype.containsCoordinate = function(coordinate) {
|
||||
// http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html
|
||||
var x = coordinate[0], y = coordinate[1];
|
||||
var vertices = this.getCoordinates();
|
||||
var inside = false;
|
||||
var xi, yi, xj, yj, intersect;
|
||||
var numVertices = vertices.length;
|
||||
for (var i = 0, j = numVertices - 1; i < numVertices; j = i++) {
|
||||
xi = vertices[i][0];
|
||||
yi = vertices[i][1];
|
||||
xj = vertices[j][0];
|
||||
yj = vertices[j][1];
|
||||
intersect = ((yi > y) != (yj > y)) &&
|
||||
(x < (xj - xi) * (y - yi) / (yj - yi) + xi);
|
||||
if (intersect) {
|
||||
inside = !inside;
|
||||
}
|
||||
}
|
||||
return inside;
|
||||
};
|
||||
@@ -0,0 +1,185 @@
|
||||
goog.provide('ol.geom.LineString');
|
||||
|
||||
goog.require('goog.asserts');
|
||||
goog.require('ol.CoordinateArray');
|
||||
goog.require('ol.geom');
|
||||
goog.require('ol.geom.Geometry');
|
||||
goog.require('ol.geom.GeometryType');
|
||||
goog.require('ol.geom.SharedVertices');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
* @extends {ol.geom.Geometry}
|
||||
* @param {ol.CoordinateArray} coordinates Vertex array (e.g.
|
||||
* [[x0, y0], [x1, y1]]).
|
||||
* @param {ol.geom.SharedVertices=} opt_shared Shared vertices.
|
||||
*/
|
||||
ol.geom.LineString = function(coordinates, opt_shared) {
|
||||
goog.base(this);
|
||||
goog.asserts.assert(goog.isArray(coordinates[0]));
|
||||
|
||||
var vertices = opt_shared,
|
||||
dimension;
|
||||
|
||||
if (!goog.isDef(vertices)) {
|
||||
dimension = coordinates[0].length;
|
||||
vertices = new ol.geom.SharedVertices({dimension: dimension});
|
||||
}
|
||||
|
||||
/**
|
||||
* @type {ol.geom.SharedVertices}
|
||||
*/
|
||||
this.vertices = vertices;
|
||||
|
||||
/**
|
||||
* @type {number}
|
||||
* @private
|
||||
*/
|
||||
this.sharedId_ = vertices.add(coordinates);
|
||||
|
||||
/**
|
||||
* @type {number}
|
||||
*/
|
||||
this.dimension = vertices.getDimension();
|
||||
goog.asserts.assert(this.dimension >= 2);
|
||||
|
||||
/**
|
||||
* @type {ol.Extent}
|
||||
* @private
|
||||
*/
|
||||
this.bounds_ = null;
|
||||
|
||||
};
|
||||
goog.inherits(ol.geom.LineString, ol.geom.Geometry);
|
||||
|
||||
|
||||
/**
|
||||
* Get a vertex coordinate value for the given dimension.
|
||||
* @param {number} index Vertex index.
|
||||
* @param {number} dim Coordinate dimension.
|
||||
* @return {number} The vertex coordinate value.
|
||||
*/
|
||||
ol.geom.LineString.prototype.get = function(index, dim) {
|
||||
return this.vertices.get(this.sharedId_, index, dim);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @return {ol.CoordinateArray} Coordinates array.
|
||||
*/
|
||||
ol.geom.LineString.prototype.getCoordinates = function() {
|
||||
var count = this.getCount();
|
||||
var coordinates = new Array(count);
|
||||
var vertex;
|
||||
for (var i = 0; i < count; ++i) {
|
||||
vertex = new Array(this.dimension);
|
||||
for (var j = 0; j < this.dimension; ++j) {
|
||||
vertex[j] = this.get(i, j);
|
||||
}
|
||||
coordinates[i] = vertex;
|
||||
}
|
||||
return coordinates;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get the count of vertices in this linestring.
|
||||
* @return {number} The vertex count.
|
||||
*/
|
||||
ol.geom.LineString.prototype.getCount = function() {
|
||||
return this.vertices.getCount(this.sharedId_);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
ol.geom.LineString.prototype.getBounds = function() {
|
||||
if (goog.isNull(this.bounds_)) {
|
||||
var dimension = this.dimension,
|
||||
vertices = this.vertices,
|
||||
id = this.sharedId_,
|
||||
count = vertices.getCount(id),
|
||||
start = vertices.getStart(id),
|
||||
end = start + (count * dimension),
|
||||
coordinates = vertices.coordinates,
|
||||
minX, maxX,
|
||||
minY, maxY,
|
||||
x, y, i;
|
||||
|
||||
minX = maxX = coordinates[start];
|
||||
minY = maxY = coordinates[start + 1];
|
||||
for (i = start + dimension; i < end; i += dimension) {
|
||||
x = coordinates[i];
|
||||
y = coordinates[i + 1];
|
||||
if (x < minX) {
|
||||
minX = x;
|
||||
} else if (x > maxX) {
|
||||
maxX = x;
|
||||
}
|
||||
if (y < minY) {
|
||||
minY = y;
|
||||
} else if (y > maxY) {
|
||||
maxY = y;
|
||||
}
|
||||
}
|
||||
this.bounds_ = [minX, maxX, minY, maxY];
|
||||
}
|
||||
return this.bounds_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
ol.geom.LineString.prototype.getType = function() {
|
||||
return ol.geom.GeometryType.LINESTRING;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get the identifier used to mark this line in the shared vertices structure.
|
||||
* @return {number} The identifier.
|
||||
*/
|
||||
ol.geom.LineString.prototype.getSharedId = function() {
|
||||
return this.sharedId_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Calculate the distance from a coordinate to this linestring.
|
||||
*
|
||||
* @param {ol.Coordinate} coordinate Coordinate.
|
||||
* @return {number} Distance from the coordinate to this linestring.
|
||||
*/
|
||||
ol.geom.LineString.prototype.distanceFromCoordinate = function(coordinate) {
|
||||
var coordinates = this.getCoordinates();
|
||||
var dist2 = Infinity;
|
||||
for (var i = 0, j = 1, len = coordinates.length; j < len; i = j++) {
|
||||
dist2 = Math.min(dist2, ol.geom.squaredDistanceToSegment(coordinate,
|
||||
[coordinates[i], coordinates[j]]));
|
||||
}
|
||||
return Math.sqrt(dist2);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
ol.geom.LineString.prototype.invalidateBounds = function() {
|
||||
this.bounds_ = null;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {number} index Vertex index.
|
||||
* @param {number} dim Coordinate dimension.
|
||||
* @param {number} value The coordinate value.
|
||||
*/
|
||||
ol.geom.LineString.prototype.set = function(index, dim, value) {
|
||||
this.invalidateBounds();
|
||||
this.vertices.set(this.sharedId_, index, dim, value);
|
||||
};
|
||||
@@ -0,0 +1,91 @@
|
||||
goog.provide('ol.geom.MultiLineString');
|
||||
|
||||
goog.require('goog.asserts');
|
||||
goog.require('ol.CoordinateArray');
|
||||
goog.require('ol.geom.AbstractCollection');
|
||||
goog.require('ol.geom.GeometryType');
|
||||
goog.require('ol.geom.LineString');
|
||||
goog.require('ol.geom.SharedVertices');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
* @extends {ol.geom.AbstractCollection}
|
||||
* @param {Array.<ol.CoordinateArray>} coordinates Coordinates array.
|
||||
* @param {ol.geom.SharedVertices=} opt_shared Shared vertices.
|
||||
*/
|
||||
ol.geom.MultiLineString = function(coordinates, opt_shared) {
|
||||
goog.base(this);
|
||||
goog.asserts.assert(goog.isArray(coordinates[0][0]));
|
||||
|
||||
var vertices = opt_shared,
|
||||
dimension;
|
||||
|
||||
if (!goog.isDef(vertices)) {
|
||||
// try to get dimension from first vertex in first line
|
||||
dimension = coordinates[0][0].length;
|
||||
vertices = new ol.geom.SharedVertices({dimension: dimension});
|
||||
}
|
||||
|
||||
var numParts = coordinates.length;
|
||||
|
||||
/**
|
||||
* @type {Array.<ol.geom.LineString>}
|
||||
*/
|
||||
this.components = new Array(numParts);
|
||||
for (var i = 0; i < numParts; ++i) {
|
||||
this.components[i] = new ol.geom.LineString(coordinates[i], vertices);
|
||||
}
|
||||
|
||||
/**
|
||||
* @type {number}
|
||||
*/
|
||||
this.dimension = vertices.getDimension();
|
||||
|
||||
};
|
||||
goog.inherits(ol.geom.MultiLineString, ol.geom.AbstractCollection);
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
ol.geom.MultiLineString.prototype.getType = function() {
|
||||
return ol.geom.GeometryType.MULTILINESTRING;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Calculate the distance from a coordinate to this multilinestring. This is
|
||||
* the closest distance of the coordinate to one of this multilinestring's
|
||||
* components.<
|
||||
*
|
||||
* @param {ol.Coordinate} coordinate Coordinate.
|
||||
* @return {number} Distance from the coordinate to this multilinestring.
|
||||
*/
|
||||
ol.geom.MultiLineString.prototype.distanceFromCoordinate =
|
||||
function(coordinate) {
|
||||
var distance = Infinity;
|
||||
for (var i = 0, ii = this.components.length; i < ii; ++i) {
|
||||
distance = Math.min(distance,
|
||||
this.components[i].distanceFromCoordinate(coordinate));
|
||||
}
|
||||
return distance;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Create a multi-linestring geometry from an array of linestring geometries.
|
||||
*
|
||||
* @param {Array.<ol.geom.LineString>} geometries Array of geometries.
|
||||
* @param {ol.geom.SharedVertices=} opt_shared Shared vertices.
|
||||
* @return {ol.geom.MultiLineString} A new geometry.
|
||||
*/
|
||||
ol.geom.MultiLineString.fromParts = function(geometries, opt_shared) {
|
||||
var count = geometries.length;
|
||||
var coordinates = new Array(count);
|
||||
for (var i = 0; i < count; ++i) {
|
||||
coordinates[i] = geometries[i].getCoordinates();
|
||||
}
|
||||
return new ol.geom.MultiLineString(coordinates, opt_shared);
|
||||
};
|
||||
@@ -0,0 +1,77 @@
|
||||
goog.provide('ol.geom.MultiPoint');
|
||||
|
||||
goog.require('goog.asserts');
|
||||
goog.require('ol.CoordinateArray');
|
||||
goog.require('ol.geom.AbstractCollection');
|
||||
goog.require('ol.geom.GeometryType');
|
||||
goog.require('ol.geom.Point');
|
||||
goog.require('ol.geom.SharedVertices');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
* @extends {ol.geom.AbstractCollection}
|
||||
* @param {ol.CoordinateArray} coordinates Coordinates array.
|
||||
* @param {ol.geom.SharedVertices=} opt_shared Shared vertices.
|
||||
*/
|
||||
ol.geom.MultiPoint = function(coordinates, opt_shared) {
|
||||
goog.base(this);
|
||||
goog.asserts.assert(goog.isArray(coordinates[0]));
|
||||
|
||||
var vertices = opt_shared,
|
||||
dimension;
|
||||
|
||||
if (!goog.isDef(vertices)) {
|
||||
// try to get dimension from first vertex
|
||||
dimension = coordinates[0].length;
|
||||
vertices = new ol.geom.SharedVertices({dimension: dimension});
|
||||
}
|
||||
|
||||
/**
|
||||
* @type {ol.geom.SharedVertices}
|
||||
*/
|
||||
this.vertices = vertices;
|
||||
|
||||
var numParts = coordinates.length;
|
||||
|
||||
/**
|
||||
* @type {Array.<ol.geom.Point>}
|
||||
*/
|
||||
this.components = new Array(numParts);
|
||||
for (var i = 0; i < numParts; ++i) {
|
||||
this.components[i] = new ol.geom.Point(coordinates[i], vertices);
|
||||
}
|
||||
|
||||
/**
|
||||
* @type {number}
|
||||
*/
|
||||
this.dimension = vertices.getDimension();
|
||||
|
||||
};
|
||||
goog.inherits(ol.geom.MultiPoint, ol.geom.AbstractCollection);
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
ol.geom.MultiPoint.prototype.getType = function() {
|
||||
return ol.geom.GeometryType.MULTIPOINT;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Create a multi-point geometry from an array of point geometries.
|
||||
*
|
||||
* @param {Array.<ol.geom.Point>} geometries Array of geometries.
|
||||
* @param {ol.geom.SharedVertices=} opt_shared Shared vertices.
|
||||
* @return {ol.geom.MultiPoint} A new geometry.
|
||||
*/
|
||||
ol.geom.MultiPoint.fromParts = function(geometries, opt_shared) {
|
||||
var count = geometries.length;
|
||||
var coordinates = new Array(count);
|
||||
for (var i = 0; i < count; ++i) {
|
||||
coordinates[i] = geometries[i].getCoordinates();
|
||||
}
|
||||
return new ol.geom.MultiPoint(coordinates, opt_shared);
|
||||
};
|
||||
@@ -0,0 +1,91 @@
|
||||
goog.provide('ol.geom.MultiPolygon');
|
||||
|
||||
goog.require('goog.asserts');
|
||||
goog.require('ol.CoordinateArray');
|
||||
goog.require('ol.geom.AbstractCollection');
|
||||
goog.require('ol.geom.GeometryType');
|
||||
goog.require('ol.geom.Polygon');
|
||||
goog.require('ol.geom.SharedVertices');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
* @extends {ol.geom.AbstractCollection}
|
||||
* @param {Array.<Array.<ol.CoordinateArray>>} coordinates Coordinates
|
||||
* array.
|
||||
* @param {ol.geom.SharedVertices=} opt_shared Shared vertices.
|
||||
*/
|
||||
ol.geom.MultiPolygon = function(coordinates, opt_shared) {
|
||||
goog.base(this);
|
||||
goog.asserts.assert(goog.isArray(coordinates[0][0][0]));
|
||||
|
||||
var vertices = opt_shared,
|
||||
dimension;
|
||||
|
||||
if (!goog.isDef(vertices)) {
|
||||
// try to get dimension from first vertex in first ring of the first poly
|
||||
dimension = coordinates[0][0][0].length;
|
||||
vertices = new ol.geom.SharedVertices({dimension: dimension});
|
||||
}
|
||||
|
||||
var numParts = coordinates.length;
|
||||
|
||||
/**
|
||||
* @type {Array.<ol.geom.Polygon>}
|
||||
*/
|
||||
this.components = new Array(numParts);
|
||||
for (var i = 0; i < numParts; ++i) {
|
||||
this.components[i] = new ol.geom.Polygon(coordinates[i], vertices);
|
||||
}
|
||||
|
||||
/**
|
||||
* @type {number}
|
||||
*/
|
||||
this.dimension = vertices.getDimension();
|
||||
|
||||
};
|
||||
goog.inherits(ol.geom.MultiPolygon, ol.geom.AbstractCollection);
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
ol.geom.MultiPolygon.prototype.getType = function() {
|
||||
return ol.geom.GeometryType.MULTIPOLYGON;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Check whether a given coordinate is inside this multipolygon.
|
||||
*
|
||||
* @param {ol.Coordinate} coordinate Coordinate.
|
||||
* @return {boolean} Whether the coordinate is inside the multipolygon.
|
||||
*/
|
||||
ol.geom.MultiPolygon.prototype.containsCoordinate = function(coordinate) {
|
||||
var containsCoordinate = false;
|
||||
for (var i = 0, ii = this.components.length; i < ii; ++i) {
|
||||
if (this.components[i].containsCoordinate(coordinate)) {
|
||||
containsCoordinate = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return containsCoordinate;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Create a multi-polygon geometry from an array of polygon geometries.
|
||||
*
|
||||
* @param {Array.<ol.geom.Polygon>} geometries Array of geometries.
|
||||
* @param {ol.geom.SharedVertices=} opt_shared Shared vertices.
|
||||
* @return {ol.geom.MultiPolygon} A new geometry.
|
||||
*/
|
||||
ol.geom.MultiPolygon.fromParts = function(geometries, opt_shared) {
|
||||
var count = geometries.length;
|
||||
var coordinates = new Array(count);
|
||||
for (var i = 0; i < count; ++i) {
|
||||
coordinates[i] = geometries[i].getCoordinates();
|
||||
}
|
||||
return new ol.geom.MultiPolygon(coordinates, opt_shared);
|
||||
};
|
||||
@@ -0,0 +1,125 @@
|
||||
goog.provide('ol.geom.Point');
|
||||
|
||||
goog.require('goog.asserts');
|
||||
goog.require('ol.Coordinate');
|
||||
goog.require('ol.geom.Geometry');
|
||||
goog.require('ol.geom.GeometryType');
|
||||
goog.require('ol.geom.SharedVertices');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
* @extends {ol.geom.Geometry}
|
||||
* @param {ol.Coordinate} coordinates Coordinates array (e.g. [x, y]).
|
||||
* @param {ol.geom.SharedVertices=} opt_shared Shared vertices.
|
||||
*/
|
||||
ol.geom.Point = function(coordinates, opt_shared) {
|
||||
goog.base(this);
|
||||
|
||||
var vertices = opt_shared,
|
||||
dimension;
|
||||
|
||||
if (!goog.isDef(vertices)) {
|
||||
dimension = coordinates.length;
|
||||
vertices = new ol.geom.SharedVertices({dimension: dimension});
|
||||
}
|
||||
|
||||
/**
|
||||
* @type {ol.geom.SharedVertices}
|
||||
*/
|
||||
this.vertices = vertices;
|
||||
|
||||
/**
|
||||
* @type {number}
|
||||
* @private
|
||||
*/
|
||||
this.sharedId_ = vertices.add([coordinates]);
|
||||
|
||||
/**
|
||||
* @type {number}
|
||||
*/
|
||||
this.dimension = vertices.getDimension();
|
||||
goog.asserts.assert(this.dimension >= 2);
|
||||
|
||||
/**
|
||||
* @type {ol.Extent}
|
||||
* @private
|
||||
*/
|
||||
this.bounds_ = null;
|
||||
|
||||
};
|
||||
goog.inherits(ol.geom.Point, ol.geom.Geometry);
|
||||
|
||||
|
||||
/**
|
||||
* @param {number} dim Coordinate dimension.
|
||||
* @return {number} The coordinate value.
|
||||
*/
|
||||
ol.geom.Point.prototype.get = function(dim) {
|
||||
return this.vertices.get(this.sharedId_, 0, dim);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
ol.geom.Point.prototype.getBounds = function() {
|
||||
if (goog.isNull(this.bounds_)) {
|
||||
var x = this.get(0),
|
||||
y = this.get(1);
|
||||
this.bounds_ = [x, x, y, y];
|
||||
}
|
||||
return this.bounds_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @return {ol.Coordinate} Coordinates array.
|
||||
*/
|
||||
ol.geom.Point.prototype.getCoordinates = function() {
|
||||
var coordinates = new Array(this.dimension);
|
||||
for (var i = 0; i < this.dimension; ++i) {
|
||||
coordinates[i] = this.get(i);
|
||||
}
|
||||
return coordinates;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
ol.geom.Point.prototype.getType = function() {
|
||||
return ol.geom.GeometryType.POINT;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get the identifier used to mark this point in the shared vertices structure.
|
||||
* @return {number} The identifier.
|
||||
*/
|
||||
ol.geom.Point.prototype.getSharedId = function() {
|
||||
return this.sharedId_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
ol.geom.Point.prototype.invalidateBounds = function() {
|
||||
this.bounds_ = null;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {number} dim Coordinate dimension.
|
||||
* @param {number} value The coordinate value.
|
||||
*/
|
||||
ol.geom.Point.prototype.set = function(dim, value) {
|
||||
if (!goog.isNull(this.bounds_) && dim <= 1) {
|
||||
this.bounds_[dim * 2] = value;
|
||||
this.bounds_[dim * 2 + 1] = value;
|
||||
}
|
||||
this.vertices.set(this.sharedId_, 0, dim, value);
|
||||
};
|
||||
@@ -0,0 +1,189 @@
|
||||
goog.provide('ol.geom.Polygon');
|
||||
|
||||
goog.require('goog.asserts');
|
||||
goog.require('ol.CoordinateArray');
|
||||
goog.require('ol.extent');
|
||||
goog.require('ol.geom.Geometry');
|
||||
goog.require('ol.geom.GeometryType');
|
||||
goog.require('ol.geom.LinearRing');
|
||||
goog.require('ol.geom.SharedVertices');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Create a polygon from an array of vertex arrays. Coordinates for the
|
||||
* exterior ring will be forced to clockwise order. Coordinates for any
|
||||
* interior rings will be forced to counter-clockwise order. In cases where
|
||||
* the opposite winding order occurs in the passed vertex arrays, they will
|
||||
* be modified in place.
|
||||
*
|
||||
* @constructor
|
||||
* @extends {ol.geom.Geometry}
|
||||
* @param {Array.<ol.CoordinateArray>} coordinates Array of rings. First
|
||||
* is outer, any remaining are inner.
|
||||
* @param {ol.geom.SharedVertices=} opt_shared Shared vertices.
|
||||
*/
|
||||
ol.geom.Polygon = function(coordinates, opt_shared) {
|
||||
goog.base(this);
|
||||
goog.asserts.assert(goog.isArray(coordinates[0][0]));
|
||||
|
||||
var vertices = opt_shared,
|
||||
dimension;
|
||||
|
||||
if (!goog.isDef(vertices)) {
|
||||
// try to get dimension from first vertex in first ring
|
||||
dimension = coordinates[0][0].length;
|
||||
vertices = new ol.geom.SharedVertices({dimension: dimension});
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {ol.Coordinate}
|
||||
*/
|
||||
this.labelPoint_ = null;
|
||||
|
||||
/**
|
||||
* @type {ol.geom.SharedVertices}
|
||||
*/
|
||||
this.vertices = vertices;
|
||||
|
||||
var numRings = coordinates.length;
|
||||
|
||||
/**
|
||||
* @type {Array.<ol.geom.LinearRing>}
|
||||
*/
|
||||
this.rings = new Array(numRings);
|
||||
var ringCoords;
|
||||
for (var i = 0; i < numRings; ++i) {
|
||||
ringCoords = coordinates[i];
|
||||
if (i === 0) {
|
||||
// force exterior ring to be clockwise
|
||||
if (!ol.geom.LinearRing.isClockwise(ringCoords)) {
|
||||
ringCoords.reverse();
|
||||
}
|
||||
} else {
|
||||
// force interior rings to be counter-clockwise
|
||||
if (ol.geom.LinearRing.isClockwise(ringCoords)) {
|
||||
ringCoords.reverse();
|
||||
}
|
||||
}
|
||||
this.rings[i] = new ol.geom.LinearRing(ringCoords, vertices);
|
||||
}
|
||||
|
||||
/**
|
||||
* @type {number}
|
||||
*/
|
||||
this.dimension = vertices.getDimension();
|
||||
goog.asserts.assert(this.dimension >= 2);
|
||||
|
||||
};
|
||||
goog.inherits(ol.geom.Polygon, ol.geom.Geometry);
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
ol.geom.Polygon.prototype.getBounds = function() {
|
||||
return this.rings[0].getBounds();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {Array.<ol.CoordinateArray>} Coordinates array.
|
||||
*/
|
||||
ol.geom.Polygon.prototype.getCoordinates = function() {
|
||||
var count = this.rings.length;
|
||||
var coordinates = new Array(count);
|
||||
for (var i = 0; i < count; ++i) {
|
||||
coordinates[i] = this.rings[i].getCoordinates();
|
||||
}
|
||||
return coordinates;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
ol.geom.Polygon.prototype.getType = function() {
|
||||
return ol.geom.GeometryType.POLYGON;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Check whether a given coordinate is inside this polygon. Note that this is a
|
||||
* fast and simple check - points on an edge or vertex of the polygon or one of
|
||||
* its inner rings are either classified inside or outside.
|
||||
*
|
||||
* @param {ol.Coordinate} coordinate Coordinate.
|
||||
* @return {boolean} Whether the coordinate is inside the polygon.
|
||||
*/
|
||||
ol.geom.Polygon.prototype.containsCoordinate = function(coordinate) {
|
||||
var rings = this.rings;
|
||||
/** @type {boolean} */
|
||||
var containsCoordinate;
|
||||
for (var i = 0, ii = rings.length; i < ii; ++i) {
|
||||
containsCoordinate = rings[i].containsCoordinate(coordinate);
|
||||
// if inner ring (i > 0) contains coordinate, polygon does not contain it
|
||||
if (i > 0) {
|
||||
containsCoordinate = !containsCoordinate;
|
||||
}
|
||||
if (!containsCoordinate) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return containsCoordinate;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Calculates a point that is guaranteed to lie in the interior of the polygon.
|
||||
* Inspired by JTS's com.vividsolutions.jts.geom.Geometry#getInteriorPoint.
|
||||
* @return {ol.Coordinate} A point which is in the interior of the polygon.
|
||||
*/
|
||||
ol.geom.Polygon.prototype.getInteriorPoint = function() {
|
||||
if (goog.isNull(this.labelPoint_)) {
|
||||
var center = ol.extent.getCenter(this.getBounds()),
|
||||
resultY = center[1],
|
||||
vertices = this.rings[0].getCoordinates(),
|
||||
intersections = [],
|
||||
maxLength = 0,
|
||||
i, vertex1, vertex2, x, segmentLength, resultX;
|
||||
|
||||
// Calculate intersections with the horizontal bounding box center line
|
||||
for (i = vertices.length - 1; i >= 1; --i) {
|
||||
vertex1 = vertices[i];
|
||||
vertex2 = vertices[i - 1];
|
||||
if ((vertex1[1] >= resultY && vertex2[1] <= resultY) ||
|
||||
(vertex1[1] <= resultY && vertex2[1] >= resultY)) {
|
||||
x = (resultY - vertex1[1]) / (vertex2[1] - vertex1[1]) *
|
||||
(vertex2[0] - vertex1[0]) + vertex1[0];
|
||||
intersections.push(x);
|
||||
}
|
||||
}
|
||||
|
||||
// Find the longest segment of the horizontal bounding box center line that
|
||||
// has its center point inside the polygon
|
||||
intersections.sort();
|
||||
for (i = intersections.length - 1; i >= 1; --i) {
|
||||
segmentLength = Math.abs(intersections[i] - intersections[i - 1]);
|
||||
if (segmentLength > maxLength) {
|
||||
x = (intersections[i] + intersections[i - 1]) / 2;
|
||||
if (this.containsCoordinate([x, resultY])) {
|
||||
maxLength = segmentLength;
|
||||
resultX = x;
|
||||
}
|
||||
}
|
||||
}
|
||||
this.labelPoint_ = [resultX, resultY];
|
||||
}
|
||||
|
||||
return this.labelPoint_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
ol.geom.Polygon.prototype.invalidateBounds = function() {
|
||||
this.rings[0].invalidateBounds();
|
||||
};
|
||||
@@ -0,0 +1,175 @@
|
||||
goog.provide('ol.geom.SharedVertices');
|
||||
|
||||
goog.require('goog.asserts');
|
||||
goog.require('ol.Coordinate');
|
||||
goog.require('ol.CoordinateArray');
|
||||
|
||||
|
||||
/**
|
||||
* @typedef {{dimension: (number),
|
||||
* offset: (ol.Coordinate|undefined)}}
|
||||
*/
|
||||
ol.geom.SharedVerticesOptions;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Provides methods for dealing with shared, flattened arrays of vertices.
|
||||
*
|
||||
* @constructor
|
||||
* @param {ol.geom.SharedVerticesOptions=} opt_options Shared vertices options.
|
||||
*/
|
||||
ol.geom.SharedVertices = function(opt_options) {
|
||||
var options = opt_options ? opt_options : {};
|
||||
|
||||
/**
|
||||
* @type {Array.<number>}
|
||||
*/
|
||||
this.coordinates = [];
|
||||
|
||||
/**
|
||||
* @type {Array.<number>}
|
||||
* @private
|
||||
*/
|
||||
this.starts_ = [];
|
||||
|
||||
/**
|
||||
* @type {Array.<number>}
|
||||
* @private
|
||||
*/
|
||||
this.counts_ = [];
|
||||
|
||||
/**
|
||||
* Number of dimensions per vertex. Default is 2.
|
||||
* @type {number}
|
||||
* @private
|
||||
*/
|
||||
this.dimension_ = options.dimension || 2;
|
||||
|
||||
/**
|
||||
* Vertex offset.
|
||||
* @type {Array.<number>}
|
||||
* @private
|
||||
*/
|
||||
this.offset_ = options.offset || null;
|
||||
goog.asserts.assert(goog.isNull(this.offset_) ||
|
||||
this.offset_.length === this.dimension_);
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Adds a vertex array to the shared coordinate array.
|
||||
* @param {ol.CoordinateArray} vertices Array of vertices.
|
||||
* @return {number} Index used to reference the added vertex array.
|
||||
*/
|
||||
ol.geom.SharedVertices.prototype.add = function(vertices) {
|
||||
var start = this.coordinates.length;
|
||||
var offset = this.offset_;
|
||||
var dimension = this.dimension_;
|
||||
var count = vertices.length;
|
||||
var vertex, index;
|
||||
for (var i = 0; i < count; ++i) {
|
||||
vertex = vertices[i];
|
||||
index = start + (i * dimension);
|
||||
for (var j = 0; j < dimension; ++j) {
|
||||
this.coordinates[index + j] = vertex[j] - (offset ? offset[j] : 0);
|
||||
}
|
||||
}
|
||||
var length = this.starts_.push(start);
|
||||
this.counts_.push(count);
|
||||
return length - 1;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {number} id The vertex array identifier (returned by add).
|
||||
* @param {number} index The vertex index.
|
||||
* @param {number} dim The coordinate dimension.
|
||||
* @return {number} The coordinate value.
|
||||
*/
|
||||
ol.geom.SharedVertices.prototype.get = function(id, index, dim) {
|
||||
goog.asserts.assert(id < this.starts_.length);
|
||||
goog.asserts.assert(dim <= this.dimension_);
|
||||
goog.asserts.assert(index < this.counts_[id]);
|
||||
var start = this.starts_[id];
|
||||
var value = this.coordinates[start + (index * this.dimension_) + dim];
|
||||
if (this.offset_) {
|
||||
value += this.offset_[dim];
|
||||
}
|
||||
return value;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {number} id The vertex array identifier (returned by add).
|
||||
* @return {number} The number of vertices in the referenced array.
|
||||
*/
|
||||
ol.geom.SharedVertices.prototype.getCount = function(id) {
|
||||
goog.asserts.assert(id < this.counts_.length);
|
||||
return this.counts_[id];
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get the array of counts. The index returned by the add method can be used
|
||||
* to look up the number of vertices.
|
||||
*
|
||||
* @return {Array.<number>} The counts array.
|
||||
*/
|
||||
ol.geom.SharedVertices.prototype.getCounts = function() {
|
||||
return this.counts_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {number} The dimension of each vertex in the array.
|
||||
*/
|
||||
ol.geom.SharedVertices.prototype.getDimension = function() {
|
||||
return this.dimension_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {Array.<number>} The offset array for vertex coordinates (or null).
|
||||
*/
|
||||
ol.geom.SharedVertices.prototype.getOffset = function() {
|
||||
return this.offset_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {number} id The vertex array identifier (returned by add).
|
||||
* @return {number} The start index in the shared vertices array.
|
||||
*/
|
||||
ol.geom.SharedVertices.prototype.getStart = function(id) {
|
||||
goog.asserts.assert(id < this.starts_.length);
|
||||
return this.starts_[id];
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get the array of start indexes.
|
||||
* @return {Array.<number>} The starts array.
|
||||
*/
|
||||
ol.geom.SharedVertices.prototype.getStarts = function() {
|
||||
return this.starts_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {number} id The vertex array identifier (returned by add).
|
||||
* @param {number} index The vertex index.
|
||||
* @param {number} dim The coordinate dimension.
|
||||
* @param {number} value The coordinate value.
|
||||
*/
|
||||
ol.geom.SharedVertices.prototype.set = function(id, index, dim, value) {
|
||||
goog.asserts.assert(id < this.starts_.length);
|
||||
goog.asserts.assert(dim <= this.dimension_);
|
||||
goog.asserts.assert(index < this.counts_[id]);
|
||||
var start = this.starts_[id];
|
||||
if (this.offset_) {
|
||||
value -= this.offset_[dim];
|
||||
}
|
||||
this.coordinates[start + (index * this.dimension_) + dim] = value;
|
||||
};
|
||||
@@ -0,0 +1,71 @@
|
||||
goog.provide('ol.geom2');
|
||||
|
||||
goog.require('goog.asserts');
|
||||
goog.require('ol.Extent');
|
||||
|
||||
|
||||
/**
|
||||
* @param {ol.structs.Buffer} buf Buffer.
|
||||
* @param {number} dim Dimension.
|
||||
* @return {ol.Extent} Extent.
|
||||
*/
|
||||
ol.geom2.getExtent = function(buf, dim) {
|
||||
var extent = new Array(2 * dim);
|
||||
var extentIndex = 0;
|
||||
var i;
|
||||
for (i = 0; i < dim; ++i) {
|
||||
extent[extentIndex++] = Infinity;
|
||||
extent[extentIndex++] = -Infinity;
|
||||
}
|
||||
var bufArr = buf.getArray();
|
||||
buf.forEachRange(function(start, stop) {
|
||||
var extentIndex, i, j;
|
||||
for (i = start; i < stop; i += dim) {
|
||||
extentIndex = 0;
|
||||
for (j = 0; j < dim; ++j) {
|
||||
extent[extentIndex++] = Math.min(extent[2 * j], bufArr[i + j]);
|
||||
extent[extentIndex++] = Math.max(extent[2 * j + 1], bufArr[i + j]);
|
||||
}
|
||||
}
|
||||
});
|
||||
return extent;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {Array.<number>} arr Array.
|
||||
* @param {number} offset Offset.
|
||||
* @param {Array.<Array.<number>>} unpackedPoints Unpacked points.
|
||||
* @param {number} dim Dimension.
|
||||
* @return {number} Offset.
|
||||
*/
|
||||
ol.geom2.packPoints = function(arr, offset, unpackedPoints, dim) {
|
||||
var n = unpackedPoints.length;
|
||||
var i, j, point;
|
||||
for (i = 0; i < n; ++i) {
|
||||
point = unpackedPoints[i];
|
||||
goog.asserts.assert(point.length == dim);
|
||||
for (j = 0; j < dim; ++j) {
|
||||
arr[offset++] = point[j];
|
||||
}
|
||||
}
|
||||
return offset;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {Array.<number>} arr Array.
|
||||
* @param {number} offset Offset.
|
||||
* @param {number} end End.
|
||||
* @param {number} dim Dimension.
|
||||
* @return {Array.<Array.<number>>} Unpacked points.
|
||||
*/
|
||||
ol.geom2.unpackPoints = function(arr, offset, end, dim) {
|
||||
var unpackedPoints = new Array((end - offset) / dim);
|
||||
var i = 0;
|
||||
var j;
|
||||
for (j = offset; j < end; j += dim) {
|
||||
unpackedPoints[i++] = arr.slice(j, j + dim);
|
||||
}
|
||||
return unpackedPoints;
|
||||
};
|
||||
@@ -0,0 +1,2 @@
|
||||
@exportSymbol ol.geom2.LineStringCollection
|
||||
@exportSymbol ol.geom2.LineStringCollection.pack
|
||||
@@ -0,0 +1,209 @@
|
||||
goog.provide('ol.geom2.LineString');
|
||||
goog.provide('ol.geom2.LineStringCollection');
|
||||
|
||||
goog.require('goog.array');
|
||||
goog.require('goog.asserts');
|
||||
goog.require('goog.object');
|
||||
goog.require('ol.geom2');
|
||||
goog.require('ol.structs.Buffer');
|
||||
|
||||
|
||||
/**
|
||||
* @typedef {Array.<Array.<number>>}
|
||||
*/
|
||||
ol.geom2.LineString;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* This is an internal class that will be removed from the API.
|
||||
* @constructor
|
||||
* @param {ol.structs.Buffer} buf Buffer.
|
||||
* @param {Object.<string, number>=} opt_ranges Ranges.
|
||||
* @param {number=} opt_dim Dimension.
|
||||
*/
|
||||
ol.geom2.LineStringCollection = function(buf, opt_ranges, opt_dim) {
|
||||
|
||||
/**
|
||||
* @type {ol.structs.Buffer}
|
||||
*/
|
||||
this.buf = buf;
|
||||
|
||||
/**
|
||||
* @type {Object.<string, number>}
|
||||
*/
|
||||
this.ranges = goog.isDef(opt_ranges) ? opt_ranges : {};
|
||||
|
||||
/**
|
||||
* @type {number}
|
||||
*/
|
||||
this.dim = goog.isDef(opt_dim) ? opt_dim : 2;
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {number} capacity Capacity.
|
||||
* @param {number=} opt_dim Dimension.
|
||||
* @return {ol.geom2.LineStringCollection} Line string collection.
|
||||
*/
|
||||
ol.geom2.LineStringCollection.createEmpty = function(capacity, opt_dim) {
|
||||
var dim = goog.isDef(opt_dim) ? opt_dim : 2;
|
||||
var buf = new ol.structs.Buffer(new Array(capacity * dim), 0);
|
||||
return new ol.geom2.LineStringCollection(buf, undefined, dim);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* This is an internal function that will be removed from the API.
|
||||
* @param {Array.<ol.geom2.LineString>} unpackedLineStrings Unpacked line
|
||||
* strings.
|
||||
* @param {number=} opt_capacity Capacity.
|
||||
* @param {number=} opt_dim Dimension.
|
||||
* @return {ol.geom2.LineStringCollection} Line string collection.
|
||||
*/
|
||||
ol.geom2.LineStringCollection.pack =
|
||||
function(unpackedLineStrings, opt_capacity, opt_dim) {
|
||||
var i;
|
||||
var n = unpackedLineStrings.length;
|
||||
var dim = goog.isDef(opt_dim) ? opt_dim :
|
||||
n > 0 ? unpackedLineStrings[0][0].length : 2;
|
||||
var capacity;
|
||||
if (goog.isDef(opt_capacity)) {
|
||||
capacity = opt_capacity;
|
||||
} else {
|
||||
capacity = 0;
|
||||
for (i = 0; i < n; ++i) {
|
||||
capacity += unpackedLineStrings[i].length;
|
||||
}
|
||||
}
|
||||
capacity *= dim;
|
||||
var arr = new Array(capacity);
|
||||
/** @type {Object.<string, number>} */
|
||||
var ranges = {};
|
||||
var offset = 0;
|
||||
var start;
|
||||
for (i = 0; i < n; ++i) {
|
||||
goog.asserts.assert(unpackedLineStrings[i].length > 1);
|
||||
start = offset;
|
||||
offset = ol.geom2.packPoints(arr, offset, unpackedLineStrings[i], dim);
|
||||
ranges[start + ''] = offset;
|
||||
}
|
||||
goog.asserts.assert(offset <= capacity);
|
||||
var buf = new ol.structs.Buffer(arr, offset);
|
||||
return new ol.geom2.LineStringCollection(buf, ranges, dim);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {ol.geom2.LineString} lineString Line string.
|
||||
* @return {number} Offset.
|
||||
*/
|
||||
ol.geom2.LineStringCollection.prototype.add = function(lineString) {
|
||||
var n = lineString.length * this.dim;
|
||||
var offset = this.buf.allocate(n);
|
||||
goog.asserts.assert(offset != -1);
|
||||
this.ranges[offset + ''] = offset + n;
|
||||
ol.geom2.packPoints(this.buf.getArray(), offset, lineString, this.dim);
|
||||
return offset;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {number} offset Offset.
|
||||
* @return {ol.geom2.LineString} Line string.
|
||||
*/
|
||||
ol.geom2.LineStringCollection.prototype.get = function(offset) {
|
||||
goog.asserts.assert(offset in this.ranges);
|
||||
var range = this.ranges[offset + ''];
|
||||
return ol.geom2.unpackPoints(
|
||||
this.buf.getArray(), offset, range, this.dim);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {number} Count.
|
||||
*/
|
||||
ol.geom2.LineStringCollection.prototype.getCount = function() {
|
||||
return goog.object.getCount(this.ranges);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {ol.Extent} Extent.
|
||||
*/
|
||||
ol.geom2.LineStringCollection.prototype.getExtent = function() {
|
||||
return ol.geom2.getExtent(this.buf, this.dim);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {Uint16Array} Indices.
|
||||
*/
|
||||
ol.geom2.LineStringCollection.prototype.getIndices = function() {
|
||||
// FIXME cache and track dirty / track output length
|
||||
var dim = this.dim;
|
||||
var offsets = goog.array.map(goog.object.getKeys(this.ranges), Number);
|
||||
goog.array.sort(offsets);
|
||||
var n = offsets.length;
|
||||
var indices = [];
|
||||
var i, j, range, offset, stop;
|
||||
for (i = 0; i < n; ++i) {
|
||||
offset = offsets[i];
|
||||
range = this.ranges[offset];
|
||||
stop = range / dim - 1;
|
||||
for (j = offset / dim; j < stop; ++j) {
|
||||
indices.push(j, j + 1);
|
||||
}
|
||||
}
|
||||
return new Uint16Array(indices);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {number} offset Offset.
|
||||
*/
|
||||
ol.geom2.LineStringCollection.prototype.remove = function(offset) {
|
||||
goog.asserts.assert(offset in this.ranges);
|
||||
var range = this.ranges[offset + ''];
|
||||
this.buf.remove(range - offset, offset);
|
||||
delete this.ranges[offset + ''];
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {number} offset Offset.
|
||||
* @param {ol.geom2.LineString} lineString Line string.
|
||||
* @return {number} Offset.
|
||||
*/
|
||||
ol.geom2.LineStringCollection.prototype.set = function(offset, lineString) {
|
||||
var dim = this.dim;
|
||||
goog.asserts.assert(offset in this.ranges);
|
||||
var range = this.ranges[offset + ''];
|
||||
if (lineString.length * dim == range - offset) {
|
||||
ol.geom2.packPoints(this.buf.getArray(), offset, lineString, dim);
|
||||
this.buf.markDirty(range - offset, offset);
|
||||
return offset;
|
||||
} else {
|
||||
this.remove(offset);
|
||||
return this.add(lineString);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {Array.<ol.geom2.LineString>} Line strings.
|
||||
*/
|
||||
ol.geom2.LineStringCollection.prototype.unpack = function() {
|
||||
var dim = this.dim;
|
||||
var n = this.getCount();
|
||||
var lineStrings = new Array(n);
|
||||
var i = 0;
|
||||
var offset, range;
|
||||
for (offset in this.ranges) {
|
||||
range = this.ranges[offset];
|
||||
lineStrings[i++] = ol.geom2.unpackPoints(
|
||||
this.buf.getArray(), Number(offset), range, dim);
|
||||
}
|
||||
return lineStrings;
|
||||
};
|
||||
@@ -0,0 +1,4 @@
|
||||
@exportSymbol ol.geom2.PointCollection
|
||||
@exportSymbol ol.geom2.PointCollection.createEmpty
|
||||
@exportSymbol ol.geom2.PointCollection.pack
|
||||
@exportProperty ol.geom2.PointCollection.prototype.add
|
||||
@@ -0,0 +1,145 @@
|
||||
goog.provide('ol.geom2.Point');
|
||||
goog.provide('ol.geom2.PointCollection');
|
||||
|
||||
goog.require('goog.asserts');
|
||||
goog.require('ol.Extent');
|
||||
goog.require('ol.geom2');
|
||||
goog.require('ol.structs.Buffer');
|
||||
|
||||
|
||||
/**
|
||||
* @typedef {Array.<number>}
|
||||
*/
|
||||
ol.geom2.Point;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* This is an internal class that will be removed from the API.
|
||||
* @constructor
|
||||
* @param {ol.structs.Buffer} buf Buffer.
|
||||
* @param {number=} opt_dim Dimension.
|
||||
*/
|
||||
ol.geom2.PointCollection = function(buf, opt_dim) {
|
||||
|
||||
/**
|
||||
* @type {ol.structs.Buffer}
|
||||
*/
|
||||
this.buf = buf;
|
||||
|
||||
/**
|
||||
* @type {number}
|
||||
*/
|
||||
this.dim = goog.isDef(opt_dim) ? opt_dim : 2;
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* This is an internal function that will be removed from the API.
|
||||
* @param {number} capacity Capacity.
|
||||
* @param {number=} opt_dim Dimension.
|
||||
* @return {ol.geom2.PointCollection} Point collection.
|
||||
*/
|
||||
ol.geom2.PointCollection.createEmpty = function(capacity, opt_dim) {
|
||||
var dim = goog.isDef(opt_dim) ? opt_dim : 2;
|
||||
var buf = new ol.structs.Buffer(new Array(capacity * dim), 0);
|
||||
return new ol.geom2.PointCollection(buf, dim);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* This is an internal function that will be removed from the API.
|
||||
* @param {Array.<ol.geom2.Point>} unpackedPoints Unpacked points.
|
||||
* @param {number=} opt_capacity Capacity.
|
||||
* @param {number=} opt_dim Dimension.
|
||||
* @return {ol.geom2.PointCollection} Point collection.
|
||||
*/
|
||||
ol.geom2.PointCollection.pack =
|
||||
function(unpackedPoints, opt_capacity, opt_dim) {
|
||||
var n = unpackedPoints.length;
|
||||
var dim = goog.isDef(opt_dim) ? opt_dim :
|
||||
n > 0 ? unpackedPoints[0].length : 2;
|
||||
var capacity = goog.isDef(opt_capacity) ? opt_capacity : n * dim;
|
||||
goog.asserts.assert(capacity >= n * dim);
|
||||
var arr = new Array(capacity);
|
||||
ol.geom2.packPoints(arr, 0, unpackedPoints, dim);
|
||||
var buf = new ol.structs.Buffer(arr, n * dim);
|
||||
return new ol.geom2.PointCollection(buf, dim);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {ol.geom2.Point} point Point.
|
||||
* @return {number} Offset.
|
||||
*/
|
||||
ol.geom2.PointCollection.prototype.add = function(point) {
|
||||
goog.asserts.assert(point.length == this.dim);
|
||||
return this.buf.add(point);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {number} offset Offset.
|
||||
* @return {ol.geom2.Point} Point.
|
||||
*/
|
||||
ol.geom2.PointCollection.prototype.get = function(offset) {
|
||||
var arr = this.buf.getArray();
|
||||
var dim = this.dim;
|
||||
goog.asserts.assert(0 <= offset && offset + dim < arr.length);
|
||||
goog.asserts.assert(offset % dim === 0);
|
||||
return arr.slice(offset, offset + dim);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {number} Count.
|
||||
*/
|
||||
ol.geom2.PointCollection.prototype.getCount = function() {
|
||||
return this.buf.getCount() / this.dim;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {ol.Extent} Extent.
|
||||
*/
|
||||
ol.geom2.PointCollection.prototype.getExtent = function() {
|
||||
return ol.geom2.getExtent(this.buf, this.dim);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {number} offset Offset.
|
||||
*/
|
||||
ol.geom2.PointCollection.prototype.remove = function(offset) {
|
||||
this.buf.remove(this.dim, offset);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {number} offset Offset.
|
||||
* @param {ol.geom2.Point} point Point.
|
||||
*/
|
||||
ol.geom2.PointCollection.prototype.set = function(offset, point) {
|
||||
this.buf.set(point, offset);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {Array.<ol.geom2.Point>} Points.
|
||||
*/
|
||||
ol.geom2.PointCollection.prototype.unpack = function() {
|
||||
var dim = this.dim;
|
||||
var n = this.getCount();
|
||||
var points = new Array(n);
|
||||
var i = 0;
|
||||
var bufArr = this.buf.getArray();
|
||||
this.buf.forEachRange(function(start, stop) {
|
||||
var j;
|
||||
for (j = start; j < stop; j += dim) {
|
||||
points[i++] = bufArr.slice(j, j + dim);
|
||||
}
|
||||
});
|
||||
goog.asserts.assert(i == n);
|
||||
return points;
|
||||
};
|
||||
@@ -0,0 +1,207 @@
|
||||
goog.provide('ol.Image');
|
||||
goog.provide('ol.ImageState');
|
||||
|
||||
goog.require('goog.array');
|
||||
goog.require('goog.asserts');
|
||||
goog.require('goog.events');
|
||||
goog.require('goog.events.EventTarget');
|
||||
goog.require('goog.events.EventType');
|
||||
goog.require('goog.object');
|
||||
goog.require('ol.Attribution');
|
||||
goog.require('ol.Extent');
|
||||
|
||||
|
||||
/**
|
||||
* @enum {number}
|
||||
*/
|
||||
ol.ImageState = {
|
||||
IDLE: 0,
|
||||
LOADING: 1,
|
||||
LOADED: 2,
|
||||
ERROR: 3
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
* @extends {goog.events.EventTarget}
|
||||
* @param {ol.Extent} extent Extent.
|
||||
* @param {number} resolution Resolution.
|
||||
* @param {string} src Image source URI.
|
||||
* @param {?string} crossOrigin Cross origin.
|
||||
* @param {Array.<ol.Attribution>} attributions Attributions.
|
||||
*/
|
||||
ol.Image = function(extent, resolution, src, crossOrigin, attributions) {
|
||||
|
||||
goog.base(this);
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {Array.<ol.Attribution>}
|
||||
*/
|
||||
this.attributions_ = attributions;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {ol.Extent}
|
||||
*/
|
||||
this.extent_ = extent;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {string}
|
||||
*/
|
||||
this.src_ = src;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {number}
|
||||
*/
|
||||
this.resolution_ = resolution;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {Image}
|
||||
*/
|
||||
this.image_ = new Image();
|
||||
if (!goog.isNull(crossOrigin)) {
|
||||
this.image_.crossOrigin = crossOrigin;
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {Object.<number, Image>}
|
||||
*/
|
||||
this.imageByContext_ = {};
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {Array.<number>}
|
||||
*/
|
||||
this.imageListenerKeys_ = null;
|
||||
|
||||
/**
|
||||
* @protected
|
||||
* @type {ol.ImageState}
|
||||
*/
|
||||
this.state = ol.ImageState.IDLE;
|
||||
};
|
||||
goog.inherits(ol.Image, goog.events.EventTarget);
|
||||
|
||||
|
||||
/**
|
||||
* @protected
|
||||
*/
|
||||
ol.Image.prototype.dispatchChangeEvent = function() {
|
||||
this.dispatchEvent(goog.events.EventType.CHANGE);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {Array.<ol.Attribution>} Attributions.
|
||||
*/
|
||||
ol.Image.prototype.getAttributions = function() {
|
||||
return this.attributions_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {ol.Extent} Extent.
|
||||
*/
|
||||
ol.Image.prototype.getExtent = function() {
|
||||
return this.extent_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {Object=} opt_context Object.
|
||||
* @return {HTMLCanvasElement|Image|HTMLVideoElement} Image.
|
||||
*/
|
||||
ol.Image.prototype.getImageElement = function(opt_context) {
|
||||
if (goog.isDef(opt_context)) {
|
||||
var image;
|
||||
var key = goog.getUid(opt_context);
|
||||
if (key in this.imageByContext_) {
|
||||
return this.imageByContext_[key];
|
||||
} else if (goog.object.isEmpty(this.imageByContext_)) {
|
||||
image = this.image_;
|
||||
} else {
|
||||
image = /** @type {Image} */ (this.image_.cloneNode(false));
|
||||
}
|
||||
this.imageByContext_[key] = image;
|
||||
return image;
|
||||
} else {
|
||||
return this.image_;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {number} Resolution.
|
||||
*/
|
||||
ol.Image.prototype.getResolution = function() {
|
||||
return this.resolution_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {ol.ImageState} State.
|
||||
*/
|
||||
ol.Image.prototype.getState = function() {
|
||||
return this.state;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Tracks loading or read errors.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
ol.Image.prototype.handleImageError_ = function() {
|
||||
this.state = ol.ImageState.ERROR;
|
||||
this.unlistenImage_();
|
||||
this.dispatchChangeEvent();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Tracks successful image load.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
ol.Image.prototype.handleImageLoad_ = function() {
|
||||
this.state = ol.ImageState.LOADED;
|
||||
this.unlistenImage_();
|
||||
this.dispatchChangeEvent();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Load not yet loaded URI.
|
||||
*/
|
||||
ol.Image.prototype.load = function() {
|
||||
if (this.state == ol.ImageState.IDLE) {
|
||||
this.state = ol.ImageState.LOADING;
|
||||
goog.asserts.assert(goog.isNull(this.imageListenerKeys_));
|
||||
this.imageListenerKeys_ = [
|
||||
goog.events.listenOnce(this.image_, goog.events.EventType.ERROR,
|
||||
this.handleImageError_, false, this),
|
||||
goog.events.listenOnce(this.image_, goog.events.EventType.LOAD,
|
||||
this.handleImageLoad_, false, this)
|
||||
];
|
||||
this.image_.src = this.src_;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Discards event handlers which listen for load completion or errors.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
ol.Image.prototype.unlistenImage_ = function() {
|
||||
goog.asserts.assert(!goog.isNull(this.imageListenerKeys_));
|
||||
goog.array.forEach(this.imageListenerKeys_, goog.events.unlistenByKey);
|
||||
this.imageListenerKeys_ = null;
|
||||
};
|
||||
@@ -0,0 +1,144 @@
|
||||
goog.provide('ol.ImageTile');
|
||||
|
||||
goog.require('goog.array');
|
||||
goog.require('goog.asserts');
|
||||
goog.require('goog.events');
|
||||
goog.require('goog.events.EventType');
|
||||
goog.require('goog.object');
|
||||
goog.require('ol.Tile');
|
||||
goog.require('ol.TileCoord');
|
||||
goog.require('ol.TileState');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
* @extends {ol.Tile}
|
||||
* @param {ol.TileCoord} tileCoord Tile coordinate.
|
||||
* @param {ol.TileState} state State.
|
||||
* @param {string} src Image source URI.
|
||||
* @param {?string} crossOrigin Cross origin.
|
||||
*/
|
||||
ol.ImageTile = function(tileCoord, state, src, crossOrigin) {
|
||||
|
||||
goog.base(this, tileCoord, state);
|
||||
|
||||
/**
|
||||
* Image URI
|
||||
*
|
||||
* @private
|
||||
* @type {string}
|
||||
*/
|
||||
this.src_ = src;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {Image}
|
||||
*/
|
||||
this.image_ = new Image();
|
||||
if (!goog.isNull(crossOrigin)) {
|
||||
this.image_.crossOrigin = crossOrigin;
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {Object.<number, Image>}
|
||||
*/
|
||||
this.imageByContext_ = {};
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {Array.<number>}
|
||||
*/
|
||||
this.imageListenerKeys_ = null;
|
||||
|
||||
};
|
||||
goog.inherits(ol.ImageTile, ol.Tile);
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
ol.ImageTile.prototype.getImage = function(opt_context) {
|
||||
if (goog.isDef(opt_context)) {
|
||||
var image;
|
||||
var key = goog.getUid(opt_context);
|
||||
if (key in this.imageByContext_) {
|
||||
return this.imageByContext_[key];
|
||||
} else if (goog.object.isEmpty(this.imageByContext_)) {
|
||||
image = this.image_;
|
||||
} else {
|
||||
image = /** @type {Image} */ (this.image_.cloneNode(false));
|
||||
}
|
||||
this.imageByContext_[key] = image;
|
||||
return image;
|
||||
} else {
|
||||
return this.image_;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
ol.ImageTile.prototype.getKey = function() {
|
||||
return this.src_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Tracks loading or read errors.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
ol.ImageTile.prototype.handleImageError_ = function() {
|
||||
this.state = ol.TileState.ERROR;
|
||||
this.unlistenImage_();
|
||||
this.dispatchChangeEvent();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Tracks successful image load.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
ol.ImageTile.prototype.handleImageLoad_ = function() {
|
||||
if (this.image_.naturalWidth && this.image_.naturalHeight) {
|
||||
this.state = ol.TileState.LOADED;
|
||||
} else {
|
||||
this.state = ol.TileState.EMPTY;
|
||||
}
|
||||
this.unlistenImage_();
|
||||
this.dispatchChangeEvent();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Load not yet loaded URI.
|
||||
*/
|
||||
ol.ImageTile.prototype.load = function() {
|
||||
if (this.state == ol.TileState.IDLE) {
|
||||
this.state = ol.TileState.LOADING;
|
||||
goog.asserts.assert(goog.isNull(this.imageListenerKeys_));
|
||||
this.imageListenerKeys_ = [
|
||||
goog.events.listenOnce(this.image_, goog.events.EventType.ERROR,
|
||||
this.handleImageError_, false, this),
|
||||
goog.events.listenOnce(this.image_, goog.events.EventType.LOAD,
|
||||
this.handleImageLoad_, false, this)
|
||||
];
|
||||
this.image_.src = this.src_;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Discards event handlers which listen for load completion or errors.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
ol.ImageTile.prototype.unlistenImage_ = function() {
|
||||
goog.asserts.assert(!goog.isNull(this.imageListenerKeys_));
|
||||
goog.array.forEach(this.imageListenerKeys_, goog.events.unlistenByKey);
|
||||
this.imageListenerKeys_ = null;
|
||||
};
|
||||
@@ -0,0 +1,46 @@
|
||||
goog.provide('ol.ImageUrlFunction');
|
||||
goog.provide('ol.ImageUrlFunctionType');
|
||||
|
||||
goog.require('ol.Size');
|
||||
|
||||
|
||||
/**
|
||||
* @typedef {function(this:ol.source.Image, ol.Extent, ol.Size,
|
||||
* ol.Projection): (string|undefined)}
|
||||
*/
|
||||
ol.ImageUrlFunctionType;
|
||||
|
||||
|
||||
/**
|
||||
* @param {string} baseUrl Base URL (may have query data).
|
||||
* @param {Object.<string,*>} params to encode in the url.
|
||||
* @param {function(string, Object.<string,*>, ol.Extent, ol.Size,
|
||||
* ol.Projection): (string|undefined)} paramsFunction params function.
|
||||
* @return {ol.ImageUrlFunctionType} Image URL function.
|
||||
*/
|
||||
ol.ImageUrlFunction.createFromParamsFunction =
|
||||
function(baseUrl, params, paramsFunction) {
|
||||
return (
|
||||
/**
|
||||
* @this {ol.source.Image}
|
||||
* @param {ol.Extent} extent Extent.
|
||||
* @param {ol.Size} size Size.
|
||||
* @param {ol.Projection} projection Projection.
|
||||
* @return {string|undefined} URL.
|
||||
*/
|
||||
function(extent, size, projection) {
|
||||
return paramsFunction(baseUrl, params, extent, size, projection);
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @this {ol.source.Image}
|
||||
* @param {ol.Extent} extent Extent.
|
||||
* @param {ol.Size} size Size.
|
||||
* @return {string|undefined} Image URL.
|
||||
*/
|
||||
ol.ImageUrlFunction.nullImageUrlFunction =
|
||||
function(extent, size) {
|
||||
return undefined;
|
||||
};
|
||||
@@ -0,0 +1,7 @@
|
||||
@exportSymbol ol.interaction.condition.altKeyOnly
|
||||
@exportSymbol ol.interaction.condition.altShiftKeysOnly
|
||||
@exportSymbol ol.interaction.condition.always
|
||||
@exportSymbol ol.interaction.condition.noModifierKeys
|
||||
@exportSymbol ol.interaction.condition.platformModifierKeyOnly
|
||||
@exportSymbol ol.interaction.condition.shiftKeyOnly
|
||||
@exportSymbol ol.interaction.condition.targetNotEditable
|
||||
@@ -0,0 +1,108 @@
|
||||
goog.provide('ol.interaction.ConditionType');
|
||||
goog.provide('ol.interaction.condition');
|
||||
|
||||
goog.require('goog.dom.TagName');
|
||||
goog.require('goog.events.EventType');
|
||||
goog.require('goog.functions');
|
||||
|
||||
|
||||
/**
|
||||
* @typedef {function(ol.MapBrowserEvent): boolean}
|
||||
*/
|
||||
ol.interaction.ConditionType;
|
||||
|
||||
|
||||
/**
|
||||
* @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event.
|
||||
* @return {boolean} True if only the alt key is pressed.
|
||||
*/
|
||||
ol.interaction.condition.altKeyOnly = function(mapBrowserEvent) {
|
||||
var browserEvent = mapBrowserEvent.browserEvent;
|
||||
return (
|
||||
browserEvent.altKey &&
|
||||
!browserEvent.platformModifierKey &&
|
||||
!browserEvent.shiftKey);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event.
|
||||
* @return {boolean} True if only the alt and shift keys are pressed.
|
||||
*/
|
||||
ol.interaction.condition.altShiftKeysOnly = function(mapBrowserEvent) {
|
||||
var browserEvent = mapBrowserEvent.browserEvent;
|
||||
return (
|
||||
browserEvent.altKey &&
|
||||
!browserEvent.platformModifierKey &&
|
||||
browserEvent.shiftKey);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event.
|
||||
* @return {boolean} True.
|
||||
*/
|
||||
ol.interaction.condition.always = goog.functions.TRUE;
|
||||
|
||||
|
||||
/**
|
||||
* @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event.
|
||||
* @return {boolean} True only the event is a click event.
|
||||
*/
|
||||
ol.interaction.condition.clickOnly = function(mapBrowserEvent) {
|
||||
var browserEvent = mapBrowserEvent.browserEvent;
|
||||
return browserEvent.type == goog.events.EventType.CLICK;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event.
|
||||
* @return {boolean} True if only the no modifier keys are pressed.
|
||||
*/
|
||||
ol.interaction.condition.noModifierKeys = function(mapBrowserEvent) {
|
||||
var browserEvent = mapBrowserEvent.browserEvent;
|
||||
return (
|
||||
!browserEvent.altKey &&
|
||||
!browserEvent.platformModifierKey &&
|
||||
!browserEvent.shiftKey);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event.
|
||||
* @return {boolean} True if only the platform modifier key is pressed.
|
||||
*/
|
||||
ol.interaction.condition.platformModifierKeyOnly = function(mapBrowserEvent) {
|
||||
var browserEvent = mapBrowserEvent.browserEvent;
|
||||
return (
|
||||
!browserEvent.altKey &&
|
||||
browserEvent.platformModifierKey &&
|
||||
!browserEvent.shiftKey);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event.
|
||||
* @return {boolean} True if only the shift key is pressed.
|
||||
*/
|
||||
ol.interaction.condition.shiftKeyOnly = function(mapBrowserEvent) {
|
||||
var browserEvent = mapBrowserEvent.browserEvent;
|
||||
return (
|
||||
!browserEvent.altKey &&
|
||||
!browserEvent.platformModifierKey &&
|
||||
browserEvent.shiftKey);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event.
|
||||
* @return {boolean} True if the target element is not editable.
|
||||
*/
|
||||
ol.interaction.condition.targetNotEditable = function(mapBrowserEvent) {
|
||||
var browserEvent = mapBrowserEvent.browserEvent;
|
||||
var tagName = browserEvent.target.tagName;
|
||||
return (
|
||||
tagName !== goog.dom.TagName.INPUT &&
|
||||
tagName !== goog.dom.TagName.SELECT &&
|
||||
tagName !== goog.dom.TagName.TEXTAREA);
|
||||
};
|
||||
@@ -0,0 +1,59 @@
|
||||
// FIXME works for View2D only
|
||||
|
||||
goog.provide('ol.interaction.DoubleClickZoom');
|
||||
|
||||
goog.require('goog.asserts');
|
||||
goog.require('ol.MapBrowserEvent');
|
||||
goog.require('ol.MapBrowserEvent.EventType');
|
||||
goog.require('ol.interaction.Interaction');
|
||||
|
||||
|
||||
/**
|
||||
* @define {number} Animation duration.
|
||||
*/
|
||||
ol.interaction.DOUBLECLICKZOOM_ANIMATION_DURATION = 250;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
* @extends {ol.interaction.Interaction}
|
||||
* @param {ol.interaction.DoubleClickZoomOptions=} opt_options Options.
|
||||
*/
|
||||
ol.interaction.DoubleClickZoom = function(opt_options) {
|
||||
|
||||
var options = goog.isDef(opt_options) ? opt_options : {};
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {number}
|
||||
*/
|
||||
this.delta_ = goog.isDef(options.delta) ? options.delta : 1;
|
||||
|
||||
goog.base(this);
|
||||
|
||||
};
|
||||
goog.inherits(ol.interaction.DoubleClickZoom, ol.interaction.Interaction);
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
ol.interaction.DoubleClickZoom.prototype.handleMapBrowserEvent =
|
||||
function(mapBrowserEvent) {
|
||||
var stopEvent = false;
|
||||
var browserEvent = mapBrowserEvent.browserEvent;
|
||||
if (mapBrowserEvent.type == ol.MapBrowserEvent.EventType.DBLCLICK &&
|
||||
mapBrowserEvent.isMouseActionButton()) {
|
||||
var map = mapBrowserEvent.map;
|
||||
var anchor = mapBrowserEvent.getCoordinate();
|
||||
var delta = browserEvent.shiftKey ? -this.delta_ : this.delta_;
|
||||
// FIXME works for View2D only
|
||||
var view = map.getView().getView2D();
|
||||
ol.interaction.Interaction.zoomByDelta(map, view, delta, anchor,
|
||||
ol.interaction.DOUBLECLICKZOOM_ANIMATION_DURATION);
|
||||
mapBrowserEvent.preventDefault();
|
||||
stopEvent = true;
|
||||
}
|
||||
return !stopEvent;
|
||||
};
|
||||
@@ -0,0 +1,156 @@
|
||||
goog.provide('ol.interaction.Drag');
|
||||
|
||||
goog.require('goog.asserts');
|
||||
goog.require('goog.events.BrowserEvent');
|
||||
goog.require('goog.functions');
|
||||
goog.require('ol.Coordinate');
|
||||
goog.require('ol.MapBrowserEvent');
|
||||
goog.require('ol.MapBrowserEvent.EventType');
|
||||
goog.require('ol.ViewHint');
|
||||
goog.require('ol.interaction.Interaction');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
* @extends {ol.interaction.Interaction}
|
||||
*/
|
||||
ol.interaction.Drag = function() {
|
||||
|
||||
goog.base(this);
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.dragging_ = false;
|
||||
|
||||
/**
|
||||
* Delta for INTERACTING view hint. Subclasses that do not want the
|
||||
* INTERACTING hint to be set should override this to 0.
|
||||
*
|
||||
* @type {number}
|
||||
*/
|
||||
this.interactingHint = 1;
|
||||
|
||||
/**
|
||||
* @type {number}
|
||||
*/
|
||||
this.startX = 0;
|
||||
|
||||
/**
|
||||
* @type {number}
|
||||
*/
|
||||
this.startY = 0;
|
||||
|
||||
/**
|
||||
* @type {number}
|
||||
*/
|
||||
this.offsetX = 0;
|
||||
|
||||
/**
|
||||
* @type {number}
|
||||
*/
|
||||
this.offsetY = 0;
|
||||
|
||||
/**
|
||||
* @type {ol.Coordinate}
|
||||
*/
|
||||
this.startCenter = null;
|
||||
|
||||
/**
|
||||
* @type {ol.Coordinate}
|
||||
*/
|
||||
this.startCoordinate = null;
|
||||
|
||||
};
|
||||
goog.inherits(ol.interaction.Drag, ol.interaction.Interaction);
|
||||
|
||||
|
||||
/**
|
||||
* @return {boolean} Whether we're dragging.
|
||||
*/
|
||||
ol.interaction.Drag.prototype.getDragging = function() {
|
||||
return this.dragging_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {ol.MapBrowserEvent} mapBrowserEvent Event.
|
||||
* @protected
|
||||
*/
|
||||
ol.interaction.Drag.prototype.handleDrag = goog.nullFunction;
|
||||
|
||||
|
||||
/**
|
||||
* @param {ol.MapBrowserEvent} mapBrowserEvent Event.
|
||||
* @protected
|
||||
*/
|
||||
ol.interaction.Drag.prototype.handleDragEnd = goog.nullFunction;
|
||||
|
||||
|
||||
/**
|
||||
* @param {ol.MapBrowserEvent} mapBrowserEvent Event.
|
||||
* @protected
|
||||
* @return {boolean} Capture dragging.
|
||||
*/
|
||||
ol.interaction.Drag.prototype.handleDragStart = goog.functions.FALSE;
|
||||
|
||||
|
||||
/**
|
||||
* @param {ol.MapBrowserEvent} mapBrowserEvent Event.
|
||||
* @protected
|
||||
*/
|
||||
ol.interaction.Drag.prototype.handleDown = goog.nullFunction;
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
ol.interaction.Drag.prototype.handleMapBrowserEvent =
|
||||
function(mapBrowserEvent) {
|
||||
var map = mapBrowserEvent.map;
|
||||
if (!map.isDef()) {
|
||||
return true;
|
||||
}
|
||||
var stopEvent = false;
|
||||
var view = map.getView();
|
||||
var browserEvent = mapBrowserEvent.browserEvent;
|
||||
if (mapBrowserEvent.type == ol.MapBrowserEvent.EventType.DOWN) {
|
||||
goog.asserts.assertInstanceof(browserEvent, goog.events.BrowserEvent);
|
||||
this.handleDown(mapBrowserEvent);
|
||||
}
|
||||
if (this.dragging_) {
|
||||
if (mapBrowserEvent.type == ol.MapBrowserEvent.EventType.DRAG) {
|
||||
goog.asserts.assertInstanceof(browserEvent, goog.events.BrowserEvent);
|
||||
this.deltaX = browserEvent.clientX - this.startX;
|
||||
this.deltaY = browserEvent.clientY - this.startY;
|
||||
this.handleDrag(mapBrowserEvent);
|
||||
} else if (mapBrowserEvent.type == ol.MapBrowserEvent.EventType.DRAGEND) {
|
||||
goog.asserts.assertInstanceof(browserEvent, goog.events.BrowserEvent);
|
||||
this.deltaX = browserEvent.clientX - this.startX;
|
||||
this.deltaY = browserEvent.clientY - this.startY;
|
||||
this.handleDragEnd(mapBrowserEvent);
|
||||
view.setHint(ol.ViewHint.INTERACTING, -this.interactingHint);
|
||||
this.dragging_ = false;
|
||||
}
|
||||
} else if (mapBrowserEvent.type == ol.MapBrowserEvent.EventType.DRAGSTART) {
|
||||
goog.asserts.assertInstanceof(browserEvent, goog.events.BrowserEvent);
|
||||
var view2DState = view.getView2D().getView2DState();
|
||||
this.startX = browserEvent.clientX;
|
||||
this.startY = browserEvent.clientY;
|
||||
this.deltaX = 0;
|
||||
this.deltaY = 0;
|
||||
this.startCenter = view2DState.center;
|
||||
this.startCoordinate = /** @type {ol.Coordinate} */
|
||||
(mapBrowserEvent.getCoordinate());
|
||||
var handled = this.handleDragStart(mapBrowserEvent);
|
||||
if (handled) {
|
||||
view.setHint(ol.ViewHint.INTERACTING, this.interactingHint);
|
||||
this.dragging_ = true;
|
||||
mapBrowserEvent.preventDefault();
|
||||
stopEvent = true;
|
||||
}
|
||||
}
|
||||
return !stopEvent;
|
||||
};
|
||||
@@ -0,0 +1,137 @@
|
||||
// FIXME works for View2D only
|
||||
|
||||
goog.provide('ol.interaction.DragPan');
|
||||
|
||||
goog.require('goog.asserts');
|
||||
goog.require('ol.Kinetic');
|
||||
goog.require('ol.PreRenderFunction');
|
||||
goog.require('ol.View2D');
|
||||
goog.require('ol.coordinate');
|
||||
goog.require('ol.interaction.ConditionType');
|
||||
goog.require('ol.interaction.Drag');
|
||||
goog.require('ol.interaction.condition');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
* @extends {ol.interaction.Drag}
|
||||
* @param {ol.interaction.DragPanOptions=} opt_options Options.
|
||||
*/
|
||||
ol.interaction.DragPan = function(opt_options) {
|
||||
|
||||
goog.base(this);
|
||||
|
||||
var options = goog.isDef(opt_options) ? opt_options : {};
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {ol.interaction.ConditionType}
|
||||
*/
|
||||
this.condition_ = goog.isDef(options.condition) ?
|
||||
options.condition : ol.interaction.condition.noModifierKeys;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {ol.Kinetic|undefined}
|
||||
*/
|
||||
this.kinetic_ = options.kinetic;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {?ol.PreRenderFunction}
|
||||
*/
|
||||
this.kineticPreRenderFn_ = null;
|
||||
|
||||
};
|
||||
goog.inherits(ol.interaction.DragPan, ol.interaction.Drag);
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
ol.interaction.DragPan.prototype.handleDrag = function(mapBrowserEvent) {
|
||||
if (this.kinetic_) {
|
||||
this.kinetic_.update(
|
||||
mapBrowserEvent.browserEvent.clientX,
|
||||
mapBrowserEvent.browserEvent.clientY);
|
||||
}
|
||||
var map = mapBrowserEvent.map;
|
||||
// FIXME works for View2D only
|
||||
var view = map.getView();
|
||||
goog.asserts.assertInstanceof(view, ol.View2D);
|
||||
var view2DState = view.getView2DState();
|
||||
var newCenter = [
|
||||
-view2DState.resolution * this.deltaX,
|
||||
view2DState.resolution * this.deltaY
|
||||
];
|
||||
ol.coordinate.rotate(newCenter, view2DState.rotation);
|
||||
ol.coordinate.add(newCenter, this.startCenter);
|
||||
map.requestRenderFrame();
|
||||
view.setCenter(newCenter);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
ol.interaction.DragPan.prototype.handleDragEnd = function(mapBrowserEvent) {
|
||||
|
||||
// FIXME works for View2D only
|
||||
|
||||
var map = mapBrowserEvent.map;
|
||||
var view = map.getView().getView2D();
|
||||
|
||||
if (this.kinetic_ && this.kinetic_.end()) {
|
||||
var view2DState = view.getView2DState();
|
||||
var distance = this.kinetic_.getDistance();
|
||||
var angle = this.kinetic_.getAngle();
|
||||
this.kineticPreRenderFn_ = this.kinetic_.pan(view2DState.center);
|
||||
map.beforeRender(this.kineticPreRenderFn_);
|
||||
|
||||
var centerpx = map.getPixelFromCoordinate(view2DState.center);
|
||||
var dest = map.getCoordinateFromPixel([
|
||||
centerpx[0] - distance * Math.cos(angle),
|
||||
centerpx[1] - distance * Math.sin(angle)
|
||||
]);
|
||||
view.setCenter(dest);
|
||||
}
|
||||
map.requestRenderFrame();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
ol.interaction.DragPan.prototype.handleDragStart = function(mapBrowserEvent) {
|
||||
var browserEvent = mapBrowserEvent.browserEvent;
|
||||
if (browserEvent.isMouseActionButton() && this.condition_(mapBrowserEvent)) {
|
||||
if (this.kinetic_) {
|
||||
this.kinetic_.begin();
|
||||
this.kinetic_.update(browserEvent.clientX, browserEvent.clientY);
|
||||
}
|
||||
var map = mapBrowserEvent.map;
|
||||
map.requestRenderFrame();
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
ol.interaction.DragPan.prototype.handleDown = function(mapBrowserEvent) {
|
||||
var map = mapBrowserEvent.map;
|
||||
// FIXME works for View2D only
|
||||
var view = map.getView();
|
||||
goog.asserts.assertInstanceof(view, ol.View2D);
|
||||
goog.asserts.assert(!goog.isNull(mapBrowserEvent.frameState));
|
||||
if (!goog.isNull(this.kineticPreRenderFn_) &&
|
||||
map.removePreRenderFunction(this.kineticPreRenderFn_)) {
|
||||
map.requestRenderFrame();
|
||||
view.setCenter(mapBrowserEvent.frameState.view2DState.center);
|
||||
this.kineticPreRenderFn_ = null;
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1 @@
|
||||
@exportClass ol.interaction.DragRotateAndZoom ol.interaction.DragRotateAndZoomOptions
|
||||
@@ -0,0 +1,127 @@
|
||||
// FIXME works for View2D only
|
||||
|
||||
goog.provide('ol.interaction.DragRotateAndZoom');
|
||||
|
||||
goog.require('goog.asserts');
|
||||
goog.require('goog.math.Vec2');
|
||||
goog.require('ol.interaction.ConditionType');
|
||||
goog.require('ol.interaction.Drag');
|
||||
goog.require('ol.interaction.Interaction');
|
||||
goog.require('ol.interaction.condition');
|
||||
|
||||
|
||||
/**
|
||||
* @define {number} Animation duration.
|
||||
*/
|
||||
ol.interaction.DRAGROTATEANDZOOM_ANIMATION_DURATION = 400;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
* @extends {ol.interaction.Drag}
|
||||
* @param {ol.interaction.DragRotateAndZoomOptions=} opt_options Options.
|
||||
*/
|
||||
ol.interaction.DragRotateAndZoom = function(opt_options) {
|
||||
|
||||
var options = goog.isDef(opt_options) ? opt_options : {};
|
||||
|
||||
goog.base(this);
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {ol.interaction.ConditionType}
|
||||
*/
|
||||
this.condition_ = goog.isDef(options.condition) ?
|
||||
options.condition : ol.interaction.condition.shiftKeyOnly;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {number|undefined}
|
||||
*/
|
||||
this.lastAngle_ = undefined;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {number|undefined}
|
||||
*/
|
||||
this.lastMagnitude_ = undefined;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {number}
|
||||
*/
|
||||
this.lastScaleDelta_ = 0;
|
||||
|
||||
};
|
||||
goog.inherits(ol.interaction.DragRotateAndZoom, ol.interaction.Drag);
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
ol.interaction.DragRotateAndZoom.prototype.handleDrag =
|
||||
function(mapBrowserEvent) {
|
||||
var browserEvent = mapBrowserEvent.browserEvent;
|
||||
var map = mapBrowserEvent.map;
|
||||
var size = map.getSize();
|
||||
var delta = new goog.math.Vec2(
|
||||
browserEvent.offsetX - size[0] / 2,
|
||||
size[1] / 2 - browserEvent.offsetY);
|
||||
var theta = Math.atan2(delta.y, delta.x);
|
||||
var magnitude = delta.magnitude();
|
||||
// FIXME works for View2D only
|
||||
var view = map.getView().getView2D();
|
||||
var view2DState = view.getView2DState();
|
||||
map.requestRenderFrame();
|
||||
if (goog.isDef(this.lastAngle_)) {
|
||||
var angleDelta = theta - this.lastAngle_;
|
||||
ol.interaction.Interaction.rotateWithoutConstraints(
|
||||
map, view, view2DState.rotation - angleDelta);
|
||||
}
|
||||
this.lastAngle_ = theta;
|
||||
if (goog.isDef(this.lastMagnitude_)) {
|
||||
var resolution = this.lastMagnitude_ * (view2DState.resolution / magnitude);
|
||||
ol.interaction.Interaction.zoomWithoutConstraints(map, view, resolution);
|
||||
}
|
||||
if (goog.isDef(this.lastMagnitude_)) {
|
||||
this.lastScaleDelta_ = this.lastMagnitude_ / magnitude;
|
||||
}
|
||||
this.lastMagnitude_ = magnitude;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
ol.interaction.DragRotateAndZoom.prototype.handleDragEnd =
|
||||
function(mapBrowserEvent) {
|
||||
var map = mapBrowserEvent.map;
|
||||
// FIXME works for View2D only
|
||||
var view = map.getView().getView2D();
|
||||
var view2DState = view.getView2DState();
|
||||
var direction = this.lastScaleDelta_ - 1;
|
||||
map.withFrozenRendering(function() {
|
||||
ol.interaction.Interaction.rotate(map, view, view2DState.rotation);
|
||||
ol.interaction.Interaction.zoom(map, view, view2DState.resolution,
|
||||
undefined, ol.interaction.DRAGROTATEANDZOOM_ANIMATION_DURATION,
|
||||
direction);
|
||||
});
|
||||
this.lastScaleDelta_ = 0;
|
||||
return true;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
ol.interaction.DragRotateAndZoom.prototype.handleDragStart =
|
||||
function(mapBrowserEvent) {
|
||||
if (this.condition_(mapBrowserEvent)) {
|
||||
this.lastAngle_ = undefined;
|
||||
this.lastMagnitude_ = undefined;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,94 @@
|
||||
goog.provide('ol.interaction.DragRotate');
|
||||
|
||||
goog.require('goog.asserts');
|
||||
goog.require('ol.interaction.ConditionType');
|
||||
goog.require('ol.interaction.Drag');
|
||||
goog.require('ol.interaction.Interaction');
|
||||
goog.require('ol.interaction.condition');
|
||||
|
||||
|
||||
/**
|
||||
* @define {number} Animation duration.
|
||||
*/
|
||||
ol.interaction.DRAGROTATE_ANIMATION_DURATION = 250;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
* @extends {ol.interaction.Drag}
|
||||
* @param {ol.interaction.DragRotateOptions=} opt_options Options.
|
||||
*/
|
||||
ol.interaction.DragRotate = function(opt_options) {
|
||||
|
||||
var options = goog.isDef(opt_options) ? opt_options : {};
|
||||
|
||||
goog.base(this);
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {ol.interaction.ConditionType}
|
||||
*/
|
||||
this.condition_ = goog.isDef(options.condition) ?
|
||||
options.condition : ol.interaction.condition.altShiftKeysOnly;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {number|undefined}
|
||||
*/
|
||||
this.lastAngle_ = undefined;
|
||||
|
||||
};
|
||||
goog.inherits(ol.interaction.DragRotate, ol.interaction.Drag);
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
ol.interaction.DragRotate.prototype.handleDrag = function(mapBrowserEvent) {
|
||||
var map = mapBrowserEvent.map;
|
||||
var size = map.getSize();
|
||||
var offset = mapBrowserEvent.getPixel();
|
||||
var theta =
|
||||
Math.atan2(size[1] / 2 - offset[1], offset[0] - size[0] / 2);
|
||||
if (goog.isDef(this.lastAngle_)) {
|
||||
var delta = theta - this.lastAngle_;
|
||||
// FIXME works for View2D only
|
||||
var view = map.getView().getView2D();
|
||||
var view2DState = view.getView2DState();
|
||||
map.requestRenderFrame();
|
||||
ol.interaction.Interaction.rotateWithoutConstraints(
|
||||
map, view, view2DState.rotation - delta);
|
||||
}
|
||||
this.lastAngle_ = theta;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
ol.interaction.DragRotate.prototype.handleDragEnd = function(mapBrowserEvent) {
|
||||
var map = mapBrowserEvent.map;
|
||||
// FIXME works for View2D only
|
||||
var view = map.getView().getView2D();
|
||||
var view2DState = view.getView2DState();
|
||||
ol.interaction.Interaction.rotate(map, view, view2DState.rotation, undefined,
|
||||
ol.interaction.DRAGROTATE_ANIMATION_DURATION);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
ol.interaction.DragRotate.prototype.handleDragStart =
|
||||
function(mapBrowserEvent) {
|
||||
var browserEvent = mapBrowserEvent.browserEvent;
|
||||
if (browserEvent.isMouseActionButton() && this.condition_(mapBrowserEvent)) {
|
||||
var map = mapBrowserEvent.map;
|
||||
map.requestRenderFrame();
|
||||
this.lastAngle_ = undefined;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,100 @@
|
||||
// FIXME draw drag box
|
||||
// FIXME works for View2D only
|
||||
|
||||
goog.provide('ol.interaction.DragZoom');
|
||||
|
||||
goog.require('goog.asserts');
|
||||
goog.require('ol.Size');
|
||||
goog.require('ol.View2D');
|
||||
goog.require('ol.control.DragBox');
|
||||
goog.require('ol.extent');
|
||||
goog.require('ol.interaction.ConditionType');
|
||||
goog.require('ol.interaction.Drag');
|
||||
goog.require('ol.interaction.condition');
|
||||
|
||||
|
||||
/**
|
||||
* @define {number} Hysterisis pixels.
|
||||
*/
|
||||
ol.SHIFT_DRAG_ZOOM_HYSTERESIS_PIXELS = 8;
|
||||
|
||||
|
||||
/**
|
||||
* @const {number}
|
||||
*/
|
||||
ol.SHIFT_DRAG_ZOOM_HYSTERESIS_PIXELS_SQUARED =
|
||||
ol.SHIFT_DRAG_ZOOM_HYSTERESIS_PIXELS *
|
||||
ol.SHIFT_DRAG_ZOOM_HYSTERESIS_PIXELS;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
* @extends {ol.interaction.Drag}
|
||||
* @param {ol.interaction.DragZoomOptions=} opt_options Options.
|
||||
*/
|
||||
ol.interaction.DragZoom = function(opt_options) {
|
||||
|
||||
goog.base(this);
|
||||
|
||||
var options = goog.isDef(opt_options) ? opt_options : {};
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {ol.interaction.ConditionType}
|
||||
*/
|
||||
this.condition_ = goog.isDef(options.condition) ?
|
||||
options.condition : ol.interaction.condition.shiftKeyOnly;
|
||||
|
||||
/**
|
||||
* @type {ol.control.DragBox}
|
||||
* @private
|
||||
*/
|
||||
this.dragBox_ = null;
|
||||
|
||||
|
||||
};
|
||||
goog.inherits(ol.interaction.DragZoom, ol.interaction.Drag);
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
ol.interaction.DragZoom.prototype.handleDragEnd =
|
||||
function(mapBrowserEvent) {
|
||||
this.dragBox_.setMap(null);
|
||||
this.dragBox_ = null;
|
||||
if (this.deltaX * this.deltaX + this.deltaY * this.deltaY >=
|
||||
ol.SHIFT_DRAG_ZOOM_HYSTERESIS_PIXELS_SQUARED) {
|
||||
var map = mapBrowserEvent.map;
|
||||
var extent = ol.extent.boundingExtent(
|
||||
[this.startCoordinate, mapBrowserEvent.getCoordinate()]);
|
||||
map.withFrozenRendering(function() {
|
||||
// FIXME works for View2D only
|
||||
var view = map.getView();
|
||||
goog.asserts.assertInstanceof(view, ol.View2D);
|
||||
var mapSize = /** @type {ol.Size} */ (map.getSize());
|
||||
view.fitExtent(extent, mapSize);
|
||||
// FIXME we should preserve rotation
|
||||
view.setRotation(0);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
ol.interaction.DragZoom.prototype.handleDragStart =
|
||||
function(mapBrowserEvent) {
|
||||
var browserEvent = mapBrowserEvent.browserEvent;
|
||||
if (browserEvent.isMouseActionButton() && this.condition_(mapBrowserEvent)) {
|
||||
this.dragBox_ = new ol.control.DragBox({
|
||||
startCoordinate: this.startCoordinate
|
||||
});
|
||||
this.dragBox_.setMap(mapBrowserEvent.map);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,181 @@
|
||||
// FIXME factor out key precondition (shift et. al)
|
||||
|
||||
goog.provide('ol.interaction.Interaction');
|
||||
|
||||
goog.require('ol.MapBrowserEvent');
|
||||
goog.require('ol.animation');
|
||||
goog.require('ol.easing');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
*/
|
||||
ol.interaction.Interaction = function() {
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event.
|
||||
* @return {boolean} Whether the map browser event should continue
|
||||
* through the chain of interactions. false means stop, true
|
||||
* means continue.
|
||||
*/
|
||||
ol.interaction.Interaction.prototype.handleMapBrowserEvent =
|
||||
goog.abstractMethod;
|
||||
|
||||
|
||||
/**
|
||||
* @param {ol.Map} map Map.
|
||||
* @param {ol.View2D} view View.
|
||||
* @param {ol.Coordinate} delta Delta.
|
||||
* @param {number=} opt_duration Duration.
|
||||
*/
|
||||
ol.interaction.Interaction.pan = function(
|
||||
map, view, delta, opt_duration) {
|
||||
var currentCenter = view.getCenter();
|
||||
if (goog.isDef(currentCenter)) {
|
||||
if (goog.isDef(opt_duration)) {
|
||||
map.beforeRender(ol.animation.pan({
|
||||
source: currentCenter,
|
||||
duration: opt_duration,
|
||||
easing: ol.easing.linear
|
||||
}));
|
||||
}
|
||||
view.setCenter([currentCenter[0] + delta[0], currentCenter[1] + delta[1]]);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {ol.Map} map Map.
|
||||
* @param {ol.View2D} view View.
|
||||
* @param {number|undefined} rotation Rotation.
|
||||
* @param {ol.Coordinate=} opt_anchor Anchor coordinate.
|
||||
* @param {number=} opt_duration Duration.
|
||||
*/
|
||||
ol.interaction.Interaction.rotate =
|
||||
function(map, view, rotation, opt_anchor, opt_duration) {
|
||||
rotation = view.constrainRotation(rotation, 0);
|
||||
ol.interaction.Interaction.rotateWithoutConstraints(
|
||||
map, view, rotation, opt_anchor, opt_duration);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {ol.Map} map Map.
|
||||
* @param {ol.View2D} view View.
|
||||
* @param {number|undefined} rotation Rotation.
|
||||
* @param {ol.Coordinate=} opt_anchor Anchor coordinate.
|
||||
* @param {number=} opt_duration Duration.
|
||||
*/
|
||||
ol.interaction.Interaction.rotateWithoutConstraints =
|
||||
function(map, view, rotation, opt_anchor, opt_duration) {
|
||||
if (goog.isDefAndNotNull(rotation)) {
|
||||
var currentRotation = view.getRotation();
|
||||
var currentCenter = view.getCenter();
|
||||
if (goog.isDef(currentRotation) && goog.isDef(currentCenter) &&
|
||||
goog.isDef(opt_duration)) {
|
||||
map.beforeRender(ol.animation.rotate({
|
||||
rotation: currentRotation,
|
||||
duration: opt_duration,
|
||||
easing: ol.easing.easeOut
|
||||
}));
|
||||
if (goog.isDef(opt_anchor)) {
|
||||
map.beforeRender(ol.animation.pan({
|
||||
source: currentCenter,
|
||||
duration: opt_duration,
|
||||
easing: ol.easing.easeOut
|
||||
}));
|
||||
}
|
||||
}
|
||||
if (goog.isDefAndNotNull(opt_anchor)) {
|
||||
var center = view.calculateCenterRotate(rotation, opt_anchor);
|
||||
map.withFrozenRendering(function() {
|
||||
view.setCenter(center);
|
||||
view.setRotation(rotation);
|
||||
});
|
||||
} else {
|
||||
view.setRotation(rotation);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {ol.Map} map Map.
|
||||
* @param {ol.View2D} view View.
|
||||
* @param {number|undefined} resolution Resolution to go to.
|
||||
* @param {ol.Coordinate=} opt_anchor Anchor coordinate.
|
||||
* @param {number=} opt_duration Duration.
|
||||
* @param {number=} opt_direction Zooming direction; > 0 indicates
|
||||
* zooming out, in which case the constraints system will select
|
||||
* the largest nearest resolution; < 0 indicates zooming in, in
|
||||
* which case the constraints system will select the smallest
|
||||
* nearest resolution; == 0 indicates that the zooming direction
|
||||
* is unknown/not relevant, in which case the constraints system
|
||||
* will select the nearest resolution. If not defined 0 is
|
||||
* assumed.
|
||||
*/
|
||||
ol.interaction.Interaction.zoom =
|
||||
function(map, view, resolution, opt_anchor, opt_duration, opt_direction) {
|
||||
resolution = view.constrainResolution(resolution, 0, opt_direction);
|
||||
ol.interaction.Interaction.zoomWithoutConstraints(
|
||||
map, view, resolution, opt_anchor, opt_duration);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {ol.Map} map Map.
|
||||
* @param {ol.View2D} view View.
|
||||
* @param {number} delta Delta from previous zoom level.
|
||||
* @param {ol.Coordinate=} opt_anchor Anchor coordinate.
|
||||
* @param {number=} opt_duration Duration.
|
||||
*/
|
||||
ol.interaction.Interaction.zoomByDelta =
|
||||
function(map, view, delta, opt_anchor, opt_duration) {
|
||||
var currentResolution = view.getResolution();
|
||||
var resolution = view.constrainResolution(currentResolution, delta, 0);
|
||||
ol.interaction.Interaction.zoomWithoutConstraints(
|
||||
map, view, resolution, opt_anchor, opt_duration);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {ol.Map} map Map.
|
||||
* @param {ol.View2D} view View.
|
||||
* @param {number|undefined} resolution Resolution to go to.
|
||||
* @param {ol.Coordinate=} opt_anchor Anchor coordinate.
|
||||
* @param {number=} opt_duration Duration.
|
||||
*/
|
||||
ol.interaction.Interaction.zoomWithoutConstraints =
|
||||
function(map, view, resolution, opt_anchor, opt_duration) {
|
||||
if (goog.isDefAndNotNull(resolution)) {
|
||||
var currentResolution = view.getResolution();
|
||||
var currentCenter = view.getCenter();
|
||||
if (goog.isDef(currentResolution) && goog.isDef(currentCenter) &&
|
||||
goog.isDef(opt_duration)) {
|
||||
map.beforeRender(ol.animation.zoom({
|
||||
resolution: currentResolution,
|
||||
duration: opt_duration,
|
||||
easing: ol.easing.easeOut
|
||||
}));
|
||||
if (goog.isDef(opt_anchor)) {
|
||||
map.beforeRender(ol.animation.pan({
|
||||
source: currentCenter,
|
||||
duration: opt_duration,
|
||||
easing: ol.easing.easeOut
|
||||
}));
|
||||
}
|
||||
}
|
||||
if (goog.isDefAndNotNull(opt_anchor)) {
|
||||
var center = view.calculateCenterZoom(resolution, opt_anchor);
|
||||
map.withFrozenRendering(function() {
|
||||
view.setCenter(center);
|
||||
view.setResolution(resolution);
|
||||
});
|
||||
} else {
|
||||
view.setResolution(resolution);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1 @@
|
||||
@exportFunction ol.interaction.defaults ol.interaction.DefaultsOptions ol.Collection
|
||||
@@ -0,0 +1,94 @@
|
||||
goog.provide('ol.interaction');
|
||||
|
||||
goog.require('ol.Collection');
|
||||
goog.require('ol.Kinetic');
|
||||
goog.require('ol.interaction.DoubleClickZoom');
|
||||
goog.require('ol.interaction.DragPan');
|
||||
goog.require('ol.interaction.DragRotate');
|
||||
goog.require('ol.interaction.DragZoom');
|
||||
goog.require('ol.interaction.KeyboardPan');
|
||||
goog.require('ol.interaction.KeyboardZoom');
|
||||
goog.require('ol.interaction.MouseWheelZoom');
|
||||
goog.require('ol.interaction.TouchPan');
|
||||
goog.require('ol.interaction.TouchRotate');
|
||||
goog.require('ol.interaction.TouchZoom');
|
||||
|
||||
|
||||
/**
|
||||
* @param {ol.interaction.DefaultsOptions=} opt_options Defaults options.
|
||||
* @return {ol.Collection} Interactions.
|
||||
*/
|
||||
ol.interaction.defaults = function(opt_options) {
|
||||
|
||||
var options = goog.isDef(opt_options) ? opt_options : {};
|
||||
|
||||
var interactions = new ol.Collection();
|
||||
|
||||
var kinetic = new ol.Kinetic(-0.005, 0.05, 100);
|
||||
|
||||
var altShiftDragRotate = goog.isDef(options.altShiftDragRotate) ?
|
||||
options.altShiftDragRotate : true;
|
||||
if (altShiftDragRotate) {
|
||||
interactions.push(new ol.interaction.DragRotate());
|
||||
}
|
||||
|
||||
var doubleClickZoom = goog.isDef(options.doubleClickZoom) ?
|
||||
options.doubleClickZoom : true;
|
||||
if (doubleClickZoom) {
|
||||
interactions.push(new ol.interaction.DoubleClickZoom({
|
||||
delta: options.zoomDelta
|
||||
}));
|
||||
}
|
||||
|
||||
var touchPan = goog.isDef(options.touchPan) ?
|
||||
options.touchPan : true;
|
||||
if (touchPan) {
|
||||
interactions.push(new ol.interaction.TouchPan({
|
||||
kinetic: kinetic
|
||||
}));
|
||||
}
|
||||
|
||||
var touchRotate = goog.isDef(options.touchRotate) ?
|
||||
options.touchRotate : true;
|
||||
if (touchRotate) {
|
||||
interactions.push(new ol.interaction.TouchRotate());
|
||||
}
|
||||
|
||||
var touchZoom = goog.isDef(options.touchZoom) ?
|
||||
options.touchZoom : true;
|
||||
if (touchZoom) {
|
||||
interactions.push(new ol.interaction.TouchZoom());
|
||||
}
|
||||
|
||||
var dragPan = goog.isDef(options.dragPan) ?
|
||||
options.dragPan : true;
|
||||
if (dragPan) {
|
||||
interactions.push(new ol.interaction.DragPan({
|
||||
kinetic: kinetic
|
||||
}));
|
||||
}
|
||||
|
||||
var keyboard = goog.isDef(options.keyboard) ?
|
||||
options.keyboard : true;
|
||||
if (keyboard) {
|
||||
interactions.push(new ol.interaction.KeyboardPan());
|
||||
interactions.push(new ol.interaction.KeyboardZoom({
|
||||
delta: options.zoomDelta
|
||||
}));
|
||||
}
|
||||
|
||||
var mouseWheelZoom = goog.isDef(options.mouseWheelZoom) ?
|
||||
options.mouseWheelZoom : true;
|
||||
if (mouseWheelZoom) {
|
||||
interactions.push(new ol.interaction.MouseWheelZoom());
|
||||
}
|
||||
|
||||
var shiftDragZoom = goog.isDef(options.shiftDragZoom) ?
|
||||
options.shiftDragZoom : true;
|
||||
if (shiftDragZoom) {
|
||||
interactions.push(new ol.interaction.DragZoom());
|
||||
}
|
||||
|
||||
return interactions;
|
||||
|
||||
};
|
||||
@@ -0,0 +1,92 @@
|
||||
// FIXME works for View2D only
|
||||
|
||||
goog.provide('ol.interaction.KeyboardPan');
|
||||
|
||||
goog.require('goog.asserts');
|
||||
goog.require('goog.events.KeyCodes');
|
||||
goog.require('goog.events.KeyHandler.EventType');
|
||||
goog.require('goog.functions');
|
||||
goog.require('ol.View2D');
|
||||
goog.require('ol.coordinate');
|
||||
goog.require('ol.interaction.ConditionType');
|
||||
goog.require('ol.interaction.Interaction');
|
||||
goog.require('ol.interaction.condition');
|
||||
|
||||
|
||||
/**
|
||||
* @define {number} Pan duration.
|
||||
*/
|
||||
ol.interaction.KEYBOARD_PAN_DURATION = 100;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
* @extends {ol.interaction.Interaction}
|
||||
* @param {ol.interaction.KeyboardPanOptions=} opt_options Options.
|
||||
*/
|
||||
ol.interaction.KeyboardPan = function(opt_options) {
|
||||
|
||||
goog.base(this);
|
||||
|
||||
var options = goog.isDef(opt_options) ? opt_options : {};
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {ol.interaction.ConditionType}
|
||||
*/
|
||||
this.condition_ = goog.isDef(options.condition) ? options.condition :
|
||||
goog.functions.and(ol.interaction.condition.noModifierKeys,
|
||||
ol.interaction.condition.targetNotEditable);
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {number}
|
||||
*/
|
||||
this.delta_ = goog.isDef(options.delta) ? options.delta : 128;
|
||||
|
||||
};
|
||||
goog.inherits(ol.interaction.KeyboardPan, ol.interaction.Interaction);
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
ol.interaction.KeyboardPan.prototype.handleMapBrowserEvent =
|
||||
function(mapBrowserEvent) {
|
||||
var stopEvent = false;
|
||||
if (mapBrowserEvent.type == goog.events.KeyHandler.EventType.KEY) {
|
||||
var keyEvent = /** @type {goog.events.KeyEvent} */
|
||||
(mapBrowserEvent.browserEvent);
|
||||
var keyCode = keyEvent.keyCode;
|
||||
if (this.condition_(mapBrowserEvent) &&
|
||||
(keyCode == goog.events.KeyCodes.DOWN ||
|
||||
keyCode == goog.events.KeyCodes.LEFT ||
|
||||
keyCode == goog.events.KeyCodes.RIGHT ||
|
||||
keyCode == goog.events.KeyCodes.UP)) {
|
||||
var map = mapBrowserEvent.map;
|
||||
// FIXME works for View2D only
|
||||
var view = map.getView();
|
||||
goog.asserts.assertInstanceof(view, ol.View2D);
|
||||
var view2DState = view.getView2DState();
|
||||
var mapUnitsDelta = view2DState.resolution * this.delta_;
|
||||
var deltaX = 0, deltaY = 0;
|
||||
if (keyCode == goog.events.KeyCodes.DOWN) {
|
||||
deltaY = -mapUnitsDelta;
|
||||
} else if (keyCode == goog.events.KeyCodes.LEFT) {
|
||||
deltaX = -mapUnitsDelta;
|
||||
} else if (keyCode == goog.events.KeyCodes.RIGHT) {
|
||||
deltaX = mapUnitsDelta;
|
||||
} else {
|
||||
deltaY = mapUnitsDelta;
|
||||
}
|
||||
var delta = [deltaX, deltaY];
|
||||
ol.coordinate.rotate(delta, view2DState.rotation);
|
||||
ol.interaction.Interaction.pan(
|
||||
map, view, delta, ol.interaction.KEYBOARD_PAN_DURATION);
|
||||
mapBrowserEvent.preventDefault();
|
||||
stopEvent = true;
|
||||
}
|
||||
}
|
||||
return !stopEvent;
|
||||
};
|
||||
@@ -0,0 +1,73 @@
|
||||
// FIXME works for View2D only
|
||||
|
||||
goog.provide('ol.interaction.KeyboardZoom');
|
||||
|
||||
goog.require('goog.asserts');
|
||||
goog.require('goog.events.KeyHandler.EventType');
|
||||
goog.require('goog.functions');
|
||||
goog.require('ol.interaction.ConditionType');
|
||||
goog.require('ol.interaction.Interaction');
|
||||
goog.require('ol.interaction.condition');
|
||||
|
||||
|
||||
/**
|
||||
* @define {number} Zoom duration.
|
||||
*/
|
||||
ol.interaction.KEYBOARD_ZOOM_DURATION = 100;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
* @param {ol.interaction.KeyboardZoomOptions=} opt_options Options.
|
||||
* @extends {ol.interaction.Interaction}
|
||||
*/
|
||||
ol.interaction.KeyboardZoom = function(opt_options) {
|
||||
|
||||
goog.base(this);
|
||||
|
||||
var options = goog.isDef(opt_options) ? opt_options : {};
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {ol.interaction.ConditionType}
|
||||
*/
|
||||
this.condition_ = goog.isDef(options.condition) ? options.condition :
|
||||
goog.functions.and(ol.interaction.condition.noModifierKeys,
|
||||
ol.interaction.condition.targetNotEditable);
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {number}
|
||||
*/
|
||||
this.delta_ = goog.isDef(options.delta) ? options.delta : 1;
|
||||
|
||||
};
|
||||
goog.inherits(ol.interaction.KeyboardZoom, ol.interaction.Interaction);
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
ol.interaction.KeyboardZoom.prototype.handleMapBrowserEvent =
|
||||
function(mapBrowserEvent) {
|
||||
var stopEvent = false;
|
||||
if (mapBrowserEvent.type == goog.events.KeyHandler.EventType.KEY) {
|
||||
var keyEvent = /** @type {goog.events.KeyEvent} */
|
||||
(mapBrowserEvent.browserEvent);
|
||||
var charCode = keyEvent.charCode;
|
||||
if (this.condition_(mapBrowserEvent) &&
|
||||
(charCode == '+'.charCodeAt(0) || charCode == '-'.charCodeAt(0))) {
|
||||
var map = mapBrowserEvent.map;
|
||||
var delta = (charCode == '+'.charCodeAt(0)) ? this.delta_ : -this.delta_;
|
||||
map.requestRenderFrame();
|
||||
// FIXME works for View2D only
|
||||
var view = map.getView().getView2D();
|
||||
ol.interaction.Interaction.zoomByDelta(map, view, delta, undefined,
|
||||
ol.interaction.KEYBOARD_ZOOM_DURATION);
|
||||
mapBrowserEvent.preventDefault();
|
||||
stopEvent = true;
|
||||
}
|
||||
}
|
||||
return !stopEvent;
|
||||
};
|
||||
@@ -0,0 +1 @@
|
||||
@exportClass ol.interaction.Modify ol.interaction.ModifyOptions
|
||||
@@ -0,0 +1,391 @@
|
||||
goog.provide('ol.interaction.Modify');
|
||||
|
||||
goog.require('goog.array');
|
||||
goog.require('goog.events');
|
||||
goog.require('goog.object');
|
||||
goog.require('ol.Feature');
|
||||
goog.require('ol.MapBrowserEvent.EventType');
|
||||
goog.require('ol.ViewHint');
|
||||
goog.require('ol.coordinate');
|
||||
goog.require('ol.extent');
|
||||
goog.require('ol.geom.AbstractCollection');
|
||||
goog.require('ol.geom.LineString');
|
||||
goog.require('ol.geom.LinearRing');
|
||||
goog.require('ol.geom.Point');
|
||||
goog.require('ol.geom.Polygon');
|
||||
goog.require('ol.interaction.Drag');
|
||||
goog.require('ol.layer.Vector');
|
||||
goog.require('ol.layer.VectorLayerEventType');
|
||||
goog.require('ol.layer.VectorLayerRenderIntent');
|
||||
goog.require('ol.structs.RTree');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
* @extends {ol.interaction.Drag}
|
||||
* @param {ol.interaction.ModifyOptions=} opt_options Options.
|
||||
*/
|
||||
ol.interaction.Modify = function(opt_options) {
|
||||
goog.base(this);
|
||||
|
||||
var options = goog.isDef(opt_options) ? opt_options : {};
|
||||
|
||||
/**
|
||||
* @type {null|function(ol.layer.Layer):boolean}
|
||||
* @private
|
||||
*/
|
||||
this.layerFilter_ = goog.isDef(options.layerFilter) ?
|
||||
options.layerFilter : null;
|
||||
|
||||
/**
|
||||
* @type {Array.<ol.layer.Layer>}
|
||||
* @private
|
||||
*/
|
||||
this.layers_ = null;
|
||||
|
||||
/**
|
||||
* @type {boolean}
|
||||
* @private
|
||||
*/
|
||||
this.modifiable_ = false;
|
||||
|
||||
/**
|
||||
* @type {number}
|
||||
* @private
|
||||
*/
|
||||
this.pixelTolerance_ = goog.isDef(options.pixelTolerance) ?
|
||||
options.pixelTolerance : 20;
|
||||
|
||||
/**
|
||||
* @type {Array}
|
||||
* @private
|
||||
*/
|
||||
this.dragVertices_ = null;
|
||||
|
||||
this.interactingHint = 0;
|
||||
};
|
||||
goog.inherits(ol.interaction.Modify, ol.interaction.Drag);
|
||||
|
||||
|
||||
/**
|
||||
* @param {ol.layer.VectorLayerEventObject} evt Event object.
|
||||
*/
|
||||
ol.interaction.Modify.prototype.addIndex = function(evt) {
|
||||
var layer = evt.target;
|
||||
var features = evt.features;
|
||||
for (var i = 0, ii = features.length; i < ii; ++i) {
|
||||
var feature = features[i];
|
||||
var geometry = feature.getGeometry();
|
||||
if (geometry instanceof ol.geom.AbstractCollection) {
|
||||
for (var j = 0, jj = geometry.components.length; j < jj; ++j) {
|
||||
this.addSegments_(layer, feature, geometry.components[j],
|
||||
[[geometry.components, j]]);
|
||||
}
|
||||
} else {
|
||||
this.addSegments_(layer, feature, geometry);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {ol.layer.Layer} layer Layer.
|
||||
*/
|
||||
ol.interaction.Modify.prototype.addLayer = function(layer) {
|
||||
var selectionData = layer.getSelectionData();
|
||||
var selectionLayer = selectionData.layer;
|
||||
var editData = selectionLayer.getEditData();
|
||||
if (goog.isNull(editData.rTree)) {
|
||||
editData.rTree = new ol.structs.RTree();
|
||||
var vertexFeature = new ol.Feature();
|
||||
vertexFeature.renderIntent = ol.layer.VectorLayerRenderIntent.HIDDEN;
|
||||
vertexFeature.setGeometry(new ol.geom.Point([NaN, NaN]));
|
||||
selectionLayer.addFeatures([vertexFeature]);
|
||||
editData.vertexFeature = vertexFeature;
|
||||
}
|
||||
this.addIndex(/** @type {ol.layer.VectorLayerEventObject} */
|
||||
({target: selectionLayer, features: goog.object.getValues(
|
||||
selectionData.selectedFeaturesByFeatureUid)}));
|
||||
goog.events.listen(selectionLayer, ol.layer.VectorLayerEventType.ADD,
|
||||
this.addIndex, false, this);
|
||||
goog.events.listen(selectionLayer, ol.layer.VectorLayerEventType.REMOVE,
|
||||
this.removeIndex, false, this);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {ol.layer.Vector} selectionLayer Selection layer.
|
||||
* @param {ol.Feature} feature Feature to add segments for.
|
||||
* @param {ol.geom.Geometry} geometry Geometry to add segments for.
|
||||
* @param {Array=} opt_parent Parent structure on the feature that the geometry
|
||||
* belongs to. This array has two values:
|
||||
* [0] the parent array;
|
||||
* [1] the index of the geometry in the parent array.
|
||||
* @private
|
||||
*/
|
||||
ol.interaction.Modify.prototype.addSegments_ =
|
||||
function(selectionLayer, feature, geometry, opt_parent) {
|
||||
var uid = goog.getUid(feature);
|
||||
var rTree = selectionLayer.getEditData().rTree;
|
||||
var vertex, segment, segmentData, coordinates;
|
||||
if (geometry instanceof ol.geom.Point) {
|
||||
vertex = geometry.getCoordinates();
|
||||
segmentData = [[vertex, vertex], feature, geometry, NaN];
|
||||
if (goog.isDef(opt_parent)) {
|
||||
segmentData.push(opt_parent);
|
||||
}
|
||||
rTree.insert(geometry.getBounds(), segmentData, uid);
|
||||
} else if (geometry instanceof ol.geom.LineString ||
|
||||
geometry instanceof ol.geom.LinearRing) {
|
||||
coordinates = geometry.getCoordinates();
|
||||
for (var i = 0, ii = coordinates.length - 1; i < ii; ++i) {
|
||||
segment = coordinates.slice(i, i + 2);
|
||||
segmentData = [segment, feature, geometry, i];
|
||||
if (opt_parent) {
|
||||
segmentData.push(opt_parent);
|
||||
}
|
||||
rTree.insert(ol.extent.boundingExtent(segment), segmentData, uid);
|
||||
}
|
||||
} else if (geometry instanceof ol.geom.Polygon) {
|
||||
for (var j = 0, jj = geometry.rings.length; j < jj; ++j) {
|
||||
this.addSegments_(selectionLayer, feature, geometry.rings[j],
|
||||
[geometry.rings, j]);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
ol.interaction.Modify.prototype.handleDragStart = function(evt) {
|
||||
this.dragVertices_ = [];
|
||||
for (var i = 0, ii = this.layers_.length; i < ii; ++i) {
|
||||
var selectionData = this.layers_[i].getSelectionData();
|
||||
var selectionLayer = selectionData.layer;
|
||||
if (!goog.isNull(selectionLayer)) {
|
||||
var editData = selectionLayer.getEditData();
|
||||
var vertexFeature = editData.vertexFeature;
|
||||
if (!goog.isNull(vertexFeature) && vertexFeature.renderIntent !=
|
||||
ol.layer.VectorLayerRenderIntent.HIDDEN) {
|
||||
var vertex = vertexFeature.getGeometry().getCoordinates();
|
||||
var vertexExtent = ol.extent.boundingExtent([vertex]);
|
||||
var segments = editData.rTree.search(vertexExtent);
|
||||
for (var j = 0, jj = segments.length; j < jj; ++j) {
|
||||
var segmentData = segments[j];
|
||||
var segment = segmentData[0];
|
||||
if (vertexFeature.renderIntent ==
|
||||
ol.layer.VectorLayerRenderIntent.TEMPORARY) {
|
||||
if (ol.coordinate.equals(segment[0], vertex)) {
|
||||
this.dragVertices_.push([selectionLayer, segmentData, 0]);
|
||||
} else {
|
||||
this.dragVertices_.push([selectionLayer, segmentData, 1]);
|
||||
}
|
||||
} else {
|
||||
this.insertVertex_(selectionLayer, segmentData, vertex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return this.modifiable_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
ol.interaction.Modify.prototype.handleDrag = function(evt) {
|
||||
var vertex = evt.getCoordinate();
|
||||
for (var i = 0, ii = this.dragVertices_.length; i < ii; ++i) {
|
||||
var dragVertex = this.dragVertices_[i];
|
||||
var selectionLayer = dragVertex[0];
|
||||
var segmentData = dragVertex[1];
|
||||
var feature = segmentData[1];
|
||||
var geometry = segmentData[2];
|
||||
var index = dragVertex[2];
|
||||
geometry.set(segmentData[3] + index, 0, vertex[0]);
|
||||
geometry.set(segmentData[3] + index, 1, vertex[1]);
|
||||
feature.getGeometry().invalidateBounds();
|
||||
|
||||
var editData = selectionLayer.getEditData();
|
||||
var vertexFeature = editData.vertexFeature;
|
||||
var vertexGeometry = vertexFeature.getGeometry();
|
||||
var segment = segmentData[0];
|
||||
editData.rTree.remove(ol.extent.boundingExtent(segment), segmentData);
|
||||
segment[index] = vertex;
|
||||
vertexGeometry.set(0, vertex[0]);
|
||||
vertexGeometry.set(1, vertex[1]);
|
||||
editData.rTree.insert(ol.extent.boundingExtent(segment), segmentData,
|
||||
goog.getUid(feature));
|
||||
|
||||
selectionLayer.updateFeatures([feature, vertexFeature]);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
ol.interaction.Modify.prototype.handleMapBrowserEvent =
|
||||
function(mapBrowserEvent) {
|
||||
if (!mapBrowserEvent.map.getView().getHints()[ol.ViewHint.INTERACTING] &&
|
||||
!this.getDragging() &&
|
||||
mapBrowserEvent.type == ol.MapBrowserEvent.EventType.MOUSEMOVE) {
|
||||
this.handleMouseMove_(mapBrowserEvent);
|
||||
}
|
||||
goog.base(this, 'handleMapBrowserEvent', mapBrowserEvent);
|
||||
return !this.modifiable_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {ol.MapBrowserEvent} evt Event.
|
||||
* @private
|
||||
*/
|
||||
ol.interaction.Modify.prototype.handleMouseMove_ = function(evt) {
|
||||
var map = evt.map;
|
||||
var layers = goog.array.filter(map.getLayerGroup().getLayers().getArray(),
|
||||
this.ignoreTemporaryLayersFilter_);
|
||||
if (!goog.isNull(this.layerFilter_)) {
|
||||
layers = goog.array.filter(layers, this.layerFilter_);
|
||||
}
|
||||
this.layers_ = layers;
|
||||
var pixel = evt.getPixel();
|
||||
var pixelCoordinate = map.getCoordinateFromPixel(pixel);
|
||||
var sortByDistance = function(a, b) {
|
||||
return ol.coordinate.closestOnSegment(pixelCoordinate, a[0])[2] -
|
||||
ol.coordinate.closestOnSegment(pixelCoordinate, b[0])[2];
|
||||
};
|
||||
|
||||
var lowerLeft = map.getCoordinateFromPixel(
|
||||
[pixel[0] - this.pixelTolerance_, pixel[1] + this.pixelTolerance_]);
|
||||
var upperRight = map.getCoordinateFromPixel(
|
||||
[pixel[0] + this.pixelTolerance_, pixel[1] - this.pixelTolerance_]);
|
||||
var box = ol.extent.boundingExtent([lowerLeft, upperRight]);
|
||||
var vertexFeature;
|
||||
this.modifiable_ = false;
|
||||
for (var i = layers.length - 1; i >= 0; --i) {
|
||||
var layer = layers[i];
|
||||
var selectionLayer = layer.getSelectionData().layer;
|
||||
if (!goog.isNull(selectionLayer)) {
|
||||
if (goog.isNull(goog.events.getListener(selectionLayer,
|
||||
ol.layer.VectorLayerEventType.ADD, this.addIndex, false, this))) {
|
||||
this.addLayer(layer);
|
||||
}
|
||||
var editData = selectionLayer.getEditData();
|
||||
vertexFeature = editData.vertexFeature;
|
||||
var segments = editData.rTree.search(box);
|
||||
var renderIntent = ol.layer.VectorLayerRenderIntent.HIDDEN;
|
||||
if (segments.length > 0) {
|
||||
segments.sort(sortByDistance);
|
||||
var segment = segments[0][0]; // the closest segment
|
||||
var geometry = vertexFeature.getGeometry();
|
||||
var vertex = /** @type {ol.Coordinate} */
|
||||
(ol.coordinate.closestOnSegment(pixelCoordinate, segment));
|
||||
var coordPixel = map.getPixelFromCoordinate(vertex);
|
||||
var pixel1 = map.getPixelFromCoordinate(segment[0]);
|
||||
var pixel2 = map.getPixelFromCoordinate(segment[1]);
|
||||
var squaredDist1 = ol.coordinate.squaredDistance(coordPixel, pixel1);
|
||||
var squaredDist2 = ol.coordinate.squaredDistance(coordPixel, pixel2);
|
||||
var dist = Math.sqrt(Math.min(squaredDist1, squaredDist2));
|
||||
renderIntent = ol.layer.VectorLayerRenderIntent.FUTURE;
|
||||
if (dist <= 10) {
|
||||
vertex = squaredDist1 > squaredDist2 ? segment[1] : segment[0];
|
||||
renderIntent = ol.layer.VectorLayerRenderIntent.TEMPORARY;
|
||||
}
|
||||
geometry.set(0, vertex[0]);
|
||||
geometry.set(1, vertex[1]);
|
||||
selectionLayer.updateFeatures([vertexFeature]);
|
||||
this.modifiable_ = true;
|
||||
}
|
||||
if (vertexFeature.renderIntent != renderIntent) {
|
||||
selectionLayer.setRenderIntent(renderIntent, [vertexFeature]);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {ol.layer.Layer} layer Layer.
|
||||
* @return {boolean} Whether the layer is no temporary vector layer.
|
||||
* @private
|
||||
*/
|
||||
ol.interaction.Modify.prototype.ignoreTemporaryLayersFilter_ = function(layer) {
|
||||
return !(layer instanceof ol.layer.Vector && layer.getTemporary());
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {ol.layer.Vector} selectionLayer Selection layer.
|
||||
* @param {Array} segmentData Segment data.
|
||||
* @param {ol.Coordinate} vertex Vertex.
|
||||
* @private
|
||||
*/
|
||||
ol.interaction.Modify.prototype.insertVertex_ =
|
||||
function(selectionLayer, segmentData, vertex) {
|
||||
var segment = segmentData[0];
|
||||
var feature = segmentData[1];
|
||||
var geometry = segmentData[2];
|
||||
var index = segmentData[3];
|
||||
var coordinates = geometry.getCoordinates();
|
||||
coordinates.splice(index + 1, 0, vertex);
|
||||
var oldGeometry = geometry;
|
||||
geometry = new geometry.constructor(coordinates);
|
||||
var parent;
|
||||
if (segmentData.length > 4) {
|
||||
parent = segmentData[4];
|
||||
parent[0][parent[1]] = geometry;
|
||||
feature.getGeometry().invalidateBounds();
|
||||
} else {
|
||||
feature.setGeometry(geometry);
|
||||
}
|
||||
var rTree = selectionLayer.getEditData().rTree;
|
||||
rTree.remove(ol.extent.boundingExtent(segment), segmentData);
|
||||
var uid = goog.getUid(feature);
|
||||
var allSegments = rTree.search(geometry.getBounds(), uid);
|
||||
for (var i = 0, ii = allSegments.length; i < ii; ++i) {
|
||||
var allSegmentsData = allSegments[i];
|
||||
if (allSegmentsData[2] === oldGeometry) {
|
||||
allSegmentsData[2] = geometry;
|
||||
if (allSegmentsData[3] > index) {
|
||||
++allSegmentsData[3];
|
||||
}
|
||||
}
|
||||
}
|
||||
var newSegment = [segment[0], vertex];
|
||||
var newSegmentData = [newSegment, feature, geometry, index];
|
||||
if (goog.isDef(parent)) {
|
||||
newSegmentData.push(parent);
|
||||
}
|
||||
rTree.insert(ol.extent.boundingExtent(newSegment), newSegmentData, uid);
|
||||
this.dragVertices_.push([selectionLayer, newSegmentData, 1]);
|
||||
newSegment = [vertex, segment[1]];
|
||||
newSegmentData = [newSegment, feature, geometry, index + 1];
|
||||
if (goog.isDef(parent)) {
|
||||
newSegmentData.push(parent);
|
||||
}
|
||||
rTree.insert(ol.extent.boundingExtent(newSegment), newSegmentData, uid);
|
||||
this.dragVertices_.push([selectionLayer, newSegmentData, 0]);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {ol.layer.VectorLayerEventObject} evt Event object.
|
||||
*/
|
||||
ol.interaction.Modify.prototype.removeIndex = function(evt) {
|
||||
var layer = evt.target;
|
||||
var rTree = layer.getEditData().rTree;
|
||||
var features = evt.features;
|
||||
for (var i = 0, ii = features.length; i < ii; ++i) {
|
||||
var feature = features[i];
|
||||
var segments = rTree.search(feature.getGeometry().getBounds(),
|
||||
goog.getUid(feature));
|
||||
for (var j = segments.length - 1; j >= 0; --j) {
|
||||
var segment = segments[j];
|
||||
rTree.remove(ol.extent.boundingExtent(segment[0]), segment);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,121 @@
|
||||
// FIXME works for View2D only
|
||||
|
||||
goog.provide('ol.interaction.MouseWheelZoom');
|
||||
|
||||
goog.require('goog.asserts');
|
||||
goog.require('goog.events.MouseWheelEvent');
|
||||
goog.require('goog.events.MouseWheelHandler.EventType');
|
||||
goog.require('goog.math');
|
||||
goog.require('ol.Coordinate');
|
||||
goog.require('ol.interaction.Interaction');
|
||||
|
||||
|
||||
/**
|
||||
* @define {number} Animation duration.
|
||||
*/
|
||||
ol.interaction.MOUSEWHEELZOOM_ANIMATION_DURATION = 250;
|
||||
|
||||
|
||||
/**
|
||||
* @define {number} Maximum delta.
|
||||
*/
|
||||
ol.interaction.MOUSEWHEELZOOM_MAXDELTA = 1;
|
||||
|
||||
|
||||
/**
|
||||
* @define {number} Timeout duration.
|
||||
*/
|
||||
ol.interaction.MOUSEWHEELZOOM_TIMEOUT_DURATION = 80;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
* @extends {ol.interaction.Interaction}
|
||||
*/
|
||||
ol.interaction.MouseWheelZoom = function() {
|
||||
|
||||
goog.base(this);
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {number}
|
||||
*/
|
||||
this.delta_ = 0;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {?ol.Coordinate}
|
||||
*/
|
||||
this.lastAnchor_ = null;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {number|undefined}
|
||||
*/
|
||||
this.startTime_ = undefined;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {number|undefined}
|
||||
*/
|
||||
this.timeoutId_ = undefined;
|
||||
|
||||
};
|
||||
goog.inherits(ol.interaction.MouseWheelZoom, ol.interaction.Interaction);
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
ol.interaction.MouseWheelZoom.prototype.handleMapBrowserEvent =
|
||||
function(mapBrowserEvent) {
|
||||
var stopEvent = false;
|
||||
if (mapBrowserEvent.type ==
|
||||
goog.events.MouseWheelHandler.EventType.MOUSEWHEEL) {
|
||||
var map = mapBrowserEvent.map;
|
||||
var mouseWheelEvent = /** @type {goog.events.MouseWheelEvent} */
|
||||
(mapBrowserEvent.browserEvent);
|
||||
goog.asserts.assertInstanceof(mouseWheelEvent, goog.events.MouseWheelEvent);
|
||||
|
||||
this.lastAnchor_ = mapBrowserEvent.getCoordinate();
|
||||
this.delta_ += mouseWheelEvent.deltaY / 3;
|
||||
|
||||
if (!goog.isDef(this.startTime_)) {
|
||||
this.startTime_ = goog.now();
|
||||
}
|
||||
|
||||
var duration = ol.interaction.MOUSEWHEELZOOM_TIMEOUT_DURATION;
|
||||
var timeLeft = Math.max(duration - (goog.now() - this.startTime_), 0);
|
||||
|
||||
goog.global.clearTimeout(this.timeoutId_);
|
||||
this.timeoutId_ = goog.global.setTimeout(
|
||||
goog.bind(this.doZoom_, this, map), timeLeft);
|
||||
|
||||
mapBrowserEvent.preventDefault();
|
||||
stopEvent = true;
|
||||
}
|
||||
return !stopEvent;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {ol.Map} map Map.
|
||||
*/
|
||||
ol.interaction.MouseWheelZoom.prototype.doZoom_ = function(map) {
|
||||
var maxDelta = ol.interaction.MOUSEWHEELZOOM_MAXDELTA;
|
||||
var delta = goog.math.clamp(this.delta_, -maxDelta, maxDelta);
|
||||
|
||||
// FIXME works for View2D only
|
||||
var view = map.getView().getView2D();
|
||||
|
||||
map.requestRenderFrame();
|
||||
ol.interaction.Interaction.zoomByDelta(map, view, -delta, this.lastAnchor_,
|
||||
ol.interaction.MOUSEWHEELZOOM_ANIMATION_DURATION);
|
||||
|
||||
this.delta_ = 0;
|
||||
this.lastAnchor_ = null;
|
||||
this.startTime_ = undefined;
|
||||
this.timeoutId_ = undefined;
|
||||
};
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user