This commit is contained in:
Éric Lemoine
2013-03-15 10:38:51 +01:00
parent 9b734a3335
commit ef9db32dda
215 changed files with 12768 additions and 8296 deletions
+2 -1
View File
@@ -8,6 +8,7 @@ goog.require('goog.dom.TagName');
goog.require('goog.events');
goog.require('goog.object');
goog.require('goog.style');
goog.require('ol');
goog.require('ol.Attribution');
goog.require('ol.FrameState');
goog.require('ol.MapEvent');
@@ -30,7 +31,7 @@ ol.control.Attribution = function(opt_options) {
this.ulElement_ = goog.dom.createElement(goog.dom.TagName.UL);
var element = goog.dom.createDom(goog.dom.TagName.DIV, {
'class': 'ol-attribution ol-unselectable'
'class': 'ol-attribution ' + ol.CSS_CLASS_UNSELECTABLE
}, this.ulElement_);
goog.base(this, {
+2 -1
View File
@@ -3,6 +3,7 @@ goog.provide('ol.control.ScaleLineUnits');
goog.require('goog.dom');
goog.require('goog.style');
goog.require('ol');
goog.require('ol.FrameState');
goog.require('ol.MapEvent');
goog.require('ol.MapEventType');
@@ -48,7 +49,7 @@ ol.control.ScaleLine = function(opt_options) {
* @type {Element}
*/
this.element_ = goog.dom.createDom(goog.dom.TagName.DIV, {
'class': 'ol-scale-line ol-unselectable'
'class': 'ol-scale-line ' + ol.CSS_CLASS_UNSELECTABLE
}, this.innerElement_);
/**
+4 -2
View File
@@ -6,6 +6,7 @@ goog.require('goog.dom');
goog.require('goog.dom.TagName');
goog.require('goog.events');
goog.require('goog.events.EventType');
goog.require('ol');
goog.require('ol.control.Control');
@@ -43,8 +44,9 @@ ol.control.Zoom = function(opt_options) {
goog.events.EventType.CLICK
], this.handleOut_, false, this);
var element = goog.dom.createDom(
goog.dom.TagName.DIV, 'ol-zoom ol-unselectable', inElement, outElement);
var cssClasses = 'ol-zoom ' + ol.CSS_CLASS_UNSELECTABLE;
var element = goog.dom.createDom(goog.dom.TagName.DIV, cssClasses, inElement,
outElement);
goog.base(this, {
element: element,
+1
View File
@@ -0,0 +1 @@
@exportClass ol.control.ZoomSlider ol.control.ZoomSliderOptions
+373
View File
@@ -0,0 +1,373 @@
// 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.asserts');
goog.require('goog.dom');
goog.require('goog.dom.TagName');
goog.require('goog.events');
goog.require('goog.fx.Dragger');
goog.require('goog.style');
goog.require('ol.MapEventType');
goog.require('ol.control.Control');
/**
* @constructor
* @extends {ol.control.Control}
* @param {ol.control.ZoomSliderOptions} zoomSliderOptions Zoom options.
*/
ol.control.ZoomSlider = function(zoomSliderOptions) {
// FIXME these should be read out from a map if not given, and only then
// fallback to the constants if they weren't defined on the map.
/**
* The minimum resolution that one can set with this control.
*
* @type {number}
* @private
*/
this.maxResolution_ = goog.isDef(zoomSliderOptions.maxResolution) ?
zoomSliderOptions.maxResolution :
ol.control.ZoomSlider.DEFAULT_MAX_RESOLUTION;
/**
* The maximum resolution that one can set with this control.
*
* @type {number}
* @private
*/
this.minResolution_ = goog.isDef(zoomSliderOptions.minResolution) ?
zoomSliderOptions.minResolution :
ol.control.ZoomSlider.DEFAULT_MIN_RESOLUTION;
goog.asserts.assert(
this.minResolution_ < this.maxResolution_,
'minResolution must be smaller than maxResolution.'
);
/**
* The range of resolutions we are handling in this slider.
*
* @type {number}
* @private
*/
this.range_ = this.maxResolution_ - this.minResolution_;
/**
* Will hold the current resolution of the view.
*
* @type {number}
* @private
*/
this.currentResolution_;
/**
* 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;
/**
* @private
* @type {Array.<?number>}
*/
this.mapListenerKeys_ = null;
/**
* @private
* @type {Array.<?number>}
*/
this.draggerListenerKeys_ = null;
var elem = this.createDom_();
this.dragger_ = this.createDraggable_(elem);
// FIXME currently only a do nothing function is bound.
goog.events.listen(elem, [
goog.events.EventType.TOUCHEND,
goog.events.EventType.CLICK
], this.handleContainerClick_, false, this);
goog.base(this, {
element: elem,
map: zoomSliderOptions.map
});
};
goog.inherits(ol.control.ZoomSlider, ol.control.Control);
/**
* The enum for available directions.
*
* @enum {number}
*/
ol.control.ZoomSlider.direction = {
VERTICAL: 0,
HORIZONTAL: 1
};
/**
* The CSS class that we'll give the zoomslider container.
*
* @const {string}
*/
ol.control.ZoomSlider.CSS_CLASS_CONTAINER = 'ol-zoomslider';
/**
* The CSS class that we'll give the zoomslider thumb.
*
* @const {string}
*/
ol.control.ZoomSlider.CSS_CLASS_THUMB =
ol.control.ZoomSlider.CSS_CLASS_CONTAINER + '-thumb';
/**
* The default value for minResolution_ when the control isn't instanciated with
* an explicit value. The default value is the resolution of the standard OSM
* tiles at zoomlevel 18.
*
* @const {number}
*/
ol.control.ZoomSlider.DEFAULT_MIN_RESOLUTION = 0.5971642833948135;
/**
* The default value for maxResolution_ when the control isn't instanciated with
* an explicit value. The default value is the resolution of the standard OSM
* tiles at zoomlevel 0.
*
* @const {number}
*/
ol.control.ZoomSlider.DEFAULT_MAX_RESOLUTION = 156543.0339;
/**
* @inheritDoc
*/
ol.control.ZoomSlider.prototype.setMap = function(map) {
goog.base(this, 'setMap', map);
this.currentResolution_ = map.getView().getResolution();
this.initMapEventListeners_();
this.initSlider_();
this.positionThumbForResolution_(this.currentResolution_);
};
/**
* Initializes the event listeners for map events.
*
* @private
*/
ol.control.ZoomSlider.prototype.initMapEventListeners_ = function() {
if (!goog.isNull(this.mapListenerKeys_)) {
goog.array.forEach(this.mapListenerKeys_, goog.events.unlistenByKey);
this.mapListenerKeys_ = null;
}
if (!goog.isNull(this.getMap())) {
this.mapListenerKeys_ = [
goog.events.listen(this.getMap(), ol.MapEventType.POSTRENDER,
this.handleMapPostRender_, undefined, this)
];
}
};
/**
* 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);
};
/**
* @param {ol.MapEvent} mapEvtObj The ol.MapEvent object.
* @private
*/
ol.control.ZoomSlider.prototype.handleMapPostRender_ = function(mapEvtObj) {
var res = mapEvtObj.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} a resolution between this.minResolution_ and
* this.maxResolution_.
* @private
*/
ol.control.ZoomSlider.prototype.resolutionForAmount_ = function(amount) {
var saneAmount = goog.math.clamp(amount, 0, 1);
return this.minResolution_ + this.range_ * saneAmount;
};
/**
* 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} an amount between 0 and 1.
* @private
*/
ol.control.ZoomSlider.prototype.amountForResolution_ = function(res) {
var saneRes = goog.math.clamp(res, this.minResolution_, this.maxResolution_);
return (saneRes - this.minResolution_) / this.range_;
};
/**
* 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(),
amountDragged = this.amountDragged_(e),
res = this.resolutionForAmount_(amountDragged);
goog.asserts.assert(res >= this.minResolution_ && res <= this.maxResolution_,
'calculated new resolution is in allowed bounds.');
if (res !== this.currentResolution_) {
this.currentResolution_ = res;
map.getView().setResolution(res);
}
};
/**
* 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;
};
/**
* Setup the DOM-structure we need for the zoomslider.
*
* @param {Element=} opt_elem The element for the slider.
* @return {Element} The correctly set up DOMElement.
* @private
*/
ol.control.ZoomSlider.prototype.createDom_ = function(opt_elem) {
var elem,
sliderCssCls = ol.control.ZoomSlider.CSS_CLASS_CONTAINER +
' ol-unselectable',
thumbCssCls = ol.control.ZoomSlider.CSS_CLASS_THUMB +
' ol-unselectable';
elem = goog.dom.createDom(goog.dom.TagName.DIV, sliderCssCls,
goog.dom.createDom(goog.dom.TagName.DIV, thumbCssCls));
return elem;
};
+70
View File
@@ -0,0 +1,70 @@
goog.provide('ol.Expression');
goog.provide('ol.ExpressionLiteral');
/**
* @constructor
* @param {string} source Expression to be evaluated.
*/
ol.Expression = function(source) {
/**
* @type {string}
* @private
*/
this.source_ = source;
};
/**
* Evaluate the expression and return the result.
*
* @param {Object=} opt_thisArg Object to use as this when evaluating the
* expression. If not provided, the global object will be used.
* @param {Object=} opt_scope Evaluation scope. All properties of this object
* will be available as variables when evaluating the expression. If not
* provided, the global object will be used.
* @return {*} Result of the expression.
*/
ol.Expression.prototype.evaluate = function(opt_thisArg, opt_scope) {
var thisArg = goog.isDef(opt_thisArg) ? opt_thisArg : goog.global,
scope = goog.isDef(opt_scope) ? opt_scope : goog.global,
names = [],
values = [];
for (var name in scope) {
names.push(name);
values.push(scope[name]);
}
var evaluator = new Function(names.join(','), 'return ' + this.source_);
return evaluator.apply(thisArg, values);
};
/**
* @constructor
* @extends {ol.Expression}
* @param {*} value Literal value.
*/
ol.ExpressionLiteral = function(value) {
/**
* @type {*}
* @private
*/
this.value_ = value;
};
goog.inherits(ol.ExpressionLiteral, ol.Expression);
/**
* @inheritDoc
*/
ol.ExpressionLiteral.prototype.evaluate = function(opt_thisArg, opt_scope) {
return this.value_;
};
+7
View File
@@ -0,0 +1,7 @@
@exportSymbol ol.Feature
@exportProperty ol.Feature.prototype.get
@exportProperty ol.Feature.prototype.getAttributes
@exportProperty ol.Feature.prototype.getGeometry
@exportProperty ol.Feature.prototype.set
@exportProperty ol.Feature.prototype.setGeometry
@exportProperty ol.Feature.prototype.setSymbolizers
+112
View File
@@ -0,0 +1,112 @@
goog.provide('ol.Feature');
goog.require('ol.Object');
goog.require('ol.geom.Geometry');
/**
* @constructor
* @extends {ol.Object}
* @param {Object=} opt_values Attributes.
*/
ol.Feature = function(opt_values) {
goog.base(this, opt_values);
/**
* @type {string|undefined}
* @private
*/
this.geometryName_;
/**
* @type {Array.<ol.style.Symbolizer>}
* @private
*/
this.symbolizers_ = null;
};
goog.inherits(ol.Feature, ol.Object);
/**
* @return {Object} 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;
};
/**
* @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;
};
/**
* @return {Array.<ol.style.SymbolizerLiteral>} Symbolizer literals.
*/
ol.Feature.prototype.getSymbolizerLiterals = function() {
var symbolizerLiterals = null;
if (!goog.isNull(this.symbolizers_)) {
var numSymbolizers = this.symbolizers_.length;
symbolizerLiterals = new Array(numSymbolizers);
for (var i = 0; i < numSymbolizers; ++i) {
symbolizerLiterals[i] = this.symbolizers_[i].createLiteral(this);
}
}
return symbolizerLiterals;
};
/**
* @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);
};
/**
* @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);
};
/**
* @param {Array.<ol.style.Symbolizer>} symbolizers Symbolizers for this
* features. 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';
+39
View File
@@ -0,0 +1,39 @@
goog.provide('ol.filter.Extent');
goog.require('ol.Extent');
goog.require('ol.filter.Filter');
/**
* @constructor
* @extends {ol.filter.Filter}
* @param {ol.Extent} extent The extent.
*/
ol.filter.Extent = function(extent) {
goog.base(this);
/**
* @type {ol.Extent}
* @private
*/
this.extent_ = extent;
};
goog.inherits(ol.filter.Extent, ol.filter.Filter);
/**
* @return {ol.Extent} The filter extent.
*/
ol.filter.Extent.prototype.getExtent = function() {
return this.extent_;
};
/**
* @inheritDoc
*/
ol.filter.Extent.prototype.applies = function(feature) {
return feature.getGeometry().getBounds().intersects(this.extent_);
};
+7
View File
@@ -0,0 +1,7 @@
@exportSymbol ol.filter.Filter
@exportSymbol ol.filter.Geometry
@exportSymbol ol.filter.Logical
@exportSymbol ol.filter.LogicalOperator
@exportProperty ol.filter.LogicalOperator.AND
@exportProperty ol.filter.LogicalOperator.OR
+24
View File
@@ -0,0 +1,24 @@
goog.provide('ol.filter.Filter');
goog.require('ol.Feature');
/**
* @constructor
* @param {function(this:ol.filter.Filter, ol.Feature)=} opt_filterFunction
* Filter function. Should return true if the passed feature passes the
* filter, false otherwise.
*/
ol.filter.Filter = function(opt_filterFunction) {
if (goog.isDef(opt_filterFunction)) {
this.applies = opt_filterFunction;
}
};
/**
* @param {ol.Feature} feature Feature to evaluate the filter against.
* @return {boolean} The provided feature passes this filter.
*/
ol.filter.Filter.prototype.applies = goog.abstractMethod;
+42
View File
@@ -0,0 +1,42 @@
goog.provide('ol.filter.Geometry');
goog.provide('ol.filter.GeometryType');
goog.require('ol.filter.Filter');
goog.require('ol.geom.GeometryType');
/**
* @constructor
* @extends {ol.filter.Filter}
* @param {ol.geom.GeometryType} type The geometry type.
*/
ol.filter.Geometry = function(type) {
goog.base(this);
/**
* @type {ol.geom.GeometryType}
* @private
*/
this.type_ = type;
};
goog.inherits(ol.filter.Geometry, ol.filter.Filter);
/**
* @inheritDoc
*/
ol.filter.Geometry.prototype.applies = function(feature) {
var geometry = feature.getGeometry();
return goog.isNull(geometry) ? false : geometry.getType() === this.type_;
};
/**
* @return {ol.geom.GeometryType} The geometry type.
*/
ol.filter.Geometry.prototype.getType = function() {
return this.type_;
};
+63
View File
@@ -0,0 +1,63 @@
goog.provide('ol.filter.Logical');
goog.provide('ol.filter.LogicalOperator');
goog.require('ol.filter.Filter');
/**
* @constructor
* @extends {ol.filter.Filter}
* @param {Array.<ol.filter.Filter>} filters Filters to and-combine.
* @param {!ol.filter.LogicalOperator} operator Operator.
*/
ol.filter.Logical = function(filters, operator) {
goog.base(this);
/**
* @type {Array.<ol.filter.Filter>}
* @private
*/
this.filters_ = filters;
/**
* @type {!ol.filter.LogicalOperator}
*/
this.operator = operator;
};
goog.inherits(ol.filter.Logical, ol.filter.Filter);
/**
* @inheritDoc
*/
ol.filter.Logical.prototype.applies = function(feature) {
var filters = this.filters_,
i = 0, ii = filters.length,
operator = this.operator,
start = operator(true, false),
result = start;
while (result === start && i < ii) {
result = operator(result, filters[i].applies(feature));
++i;
}
return result;
};
/**
* @return {Array.<ol.filter.Filter>} The filter's filters.
*/
ol.filter.Logical.prototype.getFilters = function() {
return this.filters_;
};
/**
* @enum {!Function}
*/
ol.filter.LogicalOperator = {
AND: /** @return {boolean} result. */ function(a, b) { return a && b; },
OR: /** @return {boolean} result. */ function(a, b) { return a || b; }
};
+79
View File
@@ -0,0 +1,79 @@
goog.provide('ol.geom.AbstractCollection');
goog.require('ol.Extent');
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 = Number.POSITIVE_INFINITY,
maxX,
maxY = maxX = Number.NEGATIVE_INFINITY,
components = this.components,
len = components.length,
bounds, i;
for (i = 0; i < len; ++i) {
bounds = components[i].getBounds();
minX = Math.min(bounds.minX, minX);
minY = Math.min(bounds.minY, minY);
maxX = Math.max(bounds.maxX, maxX);
maxY = Math.max(bounds.maxY, maxY);
}
this.bounds = new ol.Extent(minX, minY, maxX, 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;
+14
View File
@@ -0,0 +1,14 @@
goog.provide('ol.geom.Vertex');
goog.provide('ol.geom.VertexArray');
/**
* @typedef {Array.<number>}
*/
ol.geom.Vertex;
/**
* @typedef {Array.<ol.geom.Vertex>}
*/
ol.geom.VertexArray;
+1
View File
@@ -0,0 +1 @@
@exportSymbol ol.Expression
+6
View File
@@ -0,0 +1,6 @@
@exportSymbol ol.geom.Point
@exportSymbol ol.geom.LineString
@exportSymbol ol.geom.Polygon
@exportSymbol ol.geom.MultiPoint
@exportSymbol ol.geom.MultiLineString
@exportSymbol ol.geom.MultiPolygon
+71
View File
@@ -0,0 +1,71 @@
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;
/**
* 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;
/**
* @enum {string}
*/
ol.geom.GeometryType = {
POINT: 'point',
LINESTRING: 'linestring',
LINEARRING: 'linearring',
POLYGON: 'polygon',
MULTIPOINT: 'multipoint',
MULTILINESTRING: 'multilinestring',
MULTIPOLYGON: 'multipolygon',
GEOMETRYCOLLECTION: 'geometrycollection'
};
+48
View File
@@ -0,0 +1,48 @@
goog.provide('ol.geom.GeometryCollection');
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;
};
+35
View File
@@ -0,0 +1,35 @@
goog.provide('ol.geom.LinearRing');
goog.require('ol.geom.GeometryType');
goog.require('ol.geom.LineString');
goog.require('ol.geom.SharedVertices');
goog.require('ol.geom.VertexArray');
/**
* @constructor
* @extends {ol.geom.LineString}
* @param {ol.geom.VertexArray} 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);
/**
* @inheritDoc
*/
ol.geom.LinearRing.prototype.getType = function() {
return ol.geom.GeometryType.LINEARRING;
};
+149
View File
@@ -0,0 +1,149 @@
goog.provide('ol.geom.LineString');
goog.require('goog.asserts');
goog.require('ol.Extent');
goog.require('ol.geom.Geometry');
goog.require('ol.geom.GeometryType');
goog.require('ol.geom.SharedVertices');
goog.require('ol.geom.VertexArray');
/**
* @constructor
* @extends {ol.geom.Geometry}
* @param {ol.geom.VertexArray} 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.geom.VertexArray} 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_ = new ol.Extent(minX, minY, maxX, 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_;
};
+72
View File
@@ -0,0 +1,72 @@
goog.provide('ol.geom.MultiLineString');
goog.require('goog.asserts');
goog.require('ol.geom.AbstractCollection');
goog.require('ol.geom.GeometryType');
goog.require('ol.geom.LineString');
goog.require('ol.geom.SharedVertices');
goog.require('ol.geom.VertexArray');
/**
* @constructor
* @extends {ol.geom.AbstractCollection}
* @param {Array.<ol.geom.VertexArray>} 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;
};
/**
* 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);
};
+77
View File
@@ -0,0 +1,77 @@
goog.provide('ol.geom.MultiPoint');
goog.require('goog.asserts');
goog.require('ol.geom.AbstractCollection');
goog.require('ol.geom.GeometryType');
goog.require('ol.geom.Point');
goog.require('ol.geom.SharedVertices');
goog.require('ol.geom.VertexArray');
/**
* @constructor
* @extends {ol.geom.AbstractCollection}
* @param {ol.geom.VertexArray} 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);
};
+73
View File
@@ -0,0 +1,73 @@
goog.provide('ol.geom.MultiPolygon');
goog.require('goog.asserts');
goog.require('ol.geom.AbstractCollection');
goog.require('ol.geom.GeometryType');
goog.require('ol.geom.Polygon');
goog.require('ol.geom.SharedVertices');
goog.require('ol.geom.VertexArray');
/**
* @constructor
* @extends {ol.geom.AbstractCollection}
* @param {Array.<Array.<ol.geom.VertexArray>>} 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;
};
/**
* 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);
};
+105
View File
@@ -0,0 +1,105 @@
goog.provide('ol.geom.Point');
goog.require('goog.asserts');
goog.require('ol.Extent');
goog.require('ol.geom.Geometry');
goog.require('ol.geom.GeometryType');
goog.require('ol.geom.SharedVertices');
goog.require('ol.geom.Vertex');
/**
* @constructor
* @extends {ol.geom.Geometry}
* @param {ol.geom.Vertex} 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_ = new ol.Extent(x, y, x, y);
}
return this.bounds_;
};
/**
* @inheritDoc
* @return {ol.geom.Vertex} 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_;
};
+90
View File
@@ -0,0 +1,90 @@
goog.provide('ol.geom.Polygon');
goog.require('goog.asserts');
goog.require('ol.Extent');
goog.require('ol.geom.Geometry');
goog.require('ol.geom.GeometryType');
goog.require('ol.geom.LinearRing');
goog.require('ol.geom.SharedVertices');
goog.require('ol.geom.VertexArray');
/**
* @constructor
* @extends {ol.geom.Geometry}
* @param {Array.<ol.geom.VertexArray>} 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});
}
/**
* @type {ol.geom.SharedVertices}
*/
this.vertices = vertices;
var numRings = coordinates.length;
/**
* @type {Array.<ol.geom.LinearRing>}
*/
this.rings = new Array(numRings);
for (var i = 0; i < numRings; ++i) {
this.rings[i] = new ol.geom.LinearRing(coordinates[i], vertices);
}
/**
* @type {number}
*/
this.dimension = vertices.getDimension();
goog.asserts.assert(this.dimension >= 2);
/**
* @type {ol.Extent}
* @private
*/
this.bounds_ = null;
};
goog.inherits(ol.geom.Polygon, ol.geom.Geometry);
/**
* @inheritDoc
*/
ol.geom.Polygon.prototype.getBounds = function() {
return this.rings[0].getBounds();
};
/**
* @return {Array.<ol.geom.VertexArray>} 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;
};
+163
View File
@@ -0,0 +1,163 @@
goog.provide('ol.geom.SharedVertices');
goog.require('goog.asserts');
goog.require('ol.geom.Vertex');
goog.require('ol.geom.VertexArray');
/**
* @typedef {{dimension: (number),
* offset: (ol.geom.Vertex|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.geom.VertexArray} 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];
goog.asserts.assert(vertex.length == dimension);
if (!offset) {
Array.prototype.push.apply(this.coordinates, vertex);
} else {
index = start + (i * dimension);
for (var j = 0; j < dimension; ++j) {
this.coordinates[index + j] = vertex[j] - offset[j];
}
}
}
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_;
};
+3
View File
@@ -0,0 +1,3 @@
@exportClass ol.layer.Vector ol.layer.LayerOptions
@exportProperty ol.layer.Vector.prototype.parseFeatures
+360
View File
@@ -0,0 +1,360 @@
goog.provide('ol.layer.Vector');
goog.require('goog.events.EventType');
goog.require('ol.Feature');
goog.require('ol.geom.SharedVertices');
goog.require('ol.layer.Layer');
goog.require('ol.projection');
goog.require('ol.source.Vector');
goog.require('ol.structs.RTree');
goog.require('ol.style.Style');
/**
* @constructor
*/
ol.layer.FeatureCache = function() {
/**
* @type {Object.<string, ol.Feature>}
* @private
*/
this.idLookup_;
/**
* @type {Object.<string, ol.Feature>}
* @private
*/
this.geometryTypeIndex_;
/**
* @type {ol.structs.RTree}
* @private
*/
this.rTree_;
this.clear();
};
/**
* Clear the cache.
*/
ol.layer.FeatureCache.prototype.clear = function() {
this.idLookup_ = {};
var geometryTypeIndex = {};
for (var key in ol.geom.GeometryType) {
geometryTypeIndex[ol.geom.GeometryType[key]] = {};
}
this.geometryTypeIndex_ = geometryTypeIndex;
this.rTree_ = new ol.structs.RTree();
};
/**
* Add a feature to the cache.
* @param {ol.Feature} feature Feature to be cached.
*/
ol.layer.FeatureCache.prototype.add = function(feature) {
var id = goog.getUid(feature).toString(),
geometry = feature.getGeometry();
this.idLookup_[id] = feature;
// index by geometry type and bounding box
if (!goog.isNull(geometry)) {
var geometryType = geometry.getType();
this.geometryTypeIndex_[geometryType][id] = feature;
this.rTree_.put(geometry.getBounds(),
feature, geometryType);
}
};
/**
* @param {ol.filter.Filter=} opt_filter Optional filter.
* @return {Object.<string, ol.Feature>} Object of features, keyed by id.
*/
ol.layer.FeatureCache.prototype.getFeaturesObject = function(opt_filter) {
var i, features;
if (!goog.isDef(opt_filter)) {
features = this.idLookup_;
} else {
if (opt_filter instanceof ol.filter.Geometry) {
features = this.geometryTypeIndex_[opt_filter.getType()];
} else if (opt_filter instanceof ol.filter.Extent) {
features = this.rTree_.find(opt_filter.getExtent());
} else if (opt_filter instanceof ol.filter.Logical &&
opt_filter.operator === ol.filter.LogicalOperator.AND) {
var filters = opt_filter.getFilters();
if (filters.length === 2) {
var filter, geometryFilter, extentFilter;
for (i = 0; i <= 1; ++i) {
filter = filters[i];
if (filter instanceof ol.filter.Geometry) {
geometryFilter = filter;
} else if (filter instanceof ol.filter.Extent) {
extentFilter = filter;
}
}
if (extentFilter && geometryFilter) {
features = this.rTree_.find(
extentFilter.getExtent(), geometryFilter.getType());
}
}
}
if (!goog.isDef(features)) {
// TODO: support fast lane for other filter types
var candidates = this.idLookup_,
feature;
features = {};
for (i in candidates) {
feature = candidates[i];
if (opt_filter.applies(feature) === true) {
features[i] = feature;
}
}
}
}
return features;
};
/**
* @param {ol.filter.Geometry} filter Geometry type filter.
* @return {Array.<ol.Feature>} Array of features.
* @private
*/
ol.layer.FeatureCache.prototype.getFeaturesByGeometryType_ = function(filter) {
return goog.object.getValues(this.geometryTypeIndex_[filter.getType()]);
};
/**
* Get features by ids.
* @param {Array.<string>} ids Array of (internal) identifiers.
* @return {Array.<ol.Feature>} Array of features.
* @private
*/
ol.layer.FeatureCache.prototype.getFeaturesByIds_ = function(ids) {
var len = ids.length,
features = new Array(len),
i;
for (i = 0; i < len; ++i) {
features[i] = this.idLookup_[ids[i]];
}
return features;
};
/**
* @constructor
* @extends {ol.layer.Layer}
* @param {ol.layer.LayerOptions} layerOptions Layer options.
*/
ol.layer.Vector = function(layerOptions) {
goog.base(this, layerOptions);
/**
* @private
* @type {ol.style.Style}
*/
this.style_ = goog.isDef(layerOptions.style) ? layerOptions.style : null;
/**
* @type {ol.layer.FeatureCache}
* @private
*/
this.featureCache_ = new ol.layer.FeatureCache();
/**
* TODO: this means we need to know dimension at construction
* @type {ol.geom.SharedVertices}
* @private
*/
this.pointVertices_ = new ol.geom.SharedVertices();
/**
* TODO: this means we need to know dimension at construction
* @type {ol.geom.SharedVertices}
* @private
*/
this.lineVertices_ = new ol.geom.SharedVertices();
/**
* TODO: this means we need to know dimension at construction
* @type {ol.geom.SharedVertices}
* @private
*/
this.polygonVertices_ = new ol.geom.SharedVertices();
};
goog.inherits(ol.layer.Vector, ol.layer.Layer);
/**
* @param {Array.<ol.Feature>} features Array of features.
*/
ol.layer.Vector.prototype.addFeatures = function(features) {
for (var i = 0, ii = features.length; i < ii; ++i) {
this.featureCache_.add(features[i]);
}
// TODO: events for real - listeners want features and extent here
this.dispatchEvent(goog.events.EventType.CHANGE);
};
/**
* @return {ol.source.Vector} Source.
*/
ol.layer.Vector.prototype.getVectorSource = function() {
return /** @type {ol.source.Vector} */ (this.getSource());
};
/**
* @param {ol.filter.Filter=} opt_filter Optional filter.
* @return {Array.<ol.Feature>} Array of features.
*/
ol.layer.Vector.prototype.getFeatures = function(opt_filter) {
return goog.object.getValues(
this.featureCache_.getFeaturesObject(opt_filter));
};
/**
* @param {ol.filter.Filter=} opt_filter Optional filter.
* @return {Object.<string, ol.Feature>} Features.
*/
ol.layer.Vector.prototype.getFeaturesObject = function(opt_filter) {
return this.featureCache_.getFeaturesObject(opt_filter);
};
/**
* @return {ol.geom.SharedVertices} Shared line vertices.
*/
ol.layer.Vector.prototype.getLineVertices = function() {
return this.lineVertices_;
};
/**
* @return {ol.geom.SharedVertices} Shared point vertices.
*/
ol.layer.Vector.prototype.getPointVertices = function() {
return this.pointVertices_;
};
/**
* @return {ol.geom.SharedVertices} Shared polygon vertices.
*/
ol.layer.Vector.prototype.getPolygonVertices = function() {
return this.polygonVertices_;
};
/**
* @param {Object.<string, ol.Feature>} features Features.
* @return {Array.<Array>} symbolizers for features.
*/
ol.layer.Vector.prototype.groupFeaturesBySymbolizerLiteral =
function(features) {
var uniqueLiterals = {},
featuresBySymbolizer = [],
style = this.style_,
i, j, l, feature, literals, numLiterals, literal, uniqueLiteral, key;
for (i in features) {
feature = features[i];
literals = feature.getSymbolizerLiterals();
if (goog.isNull(literals)) {
literals = goog.isNull(style) ?
ol.style.Style.applyDefaultStyle(feature) :
style.apply(feature);
}
numLiterals = literals.length;
for (j = 0; j < numLiterals; ++j) {
literal = literals[j];
for (l in uniqueLiterals) {
uniqueLiteral = featuresBySymbolizer[uniqueLiterals[l]][1];
if (literal.equals(uniqueLiteral)) {
literal = uniqueLiteral;
break;
}
}
key = goog.getUid(literal);
if (!goog.object.containsKey(uniqueLiterals, key)) {
uniqueLiterals[key] = featuresBySymbolizer.length;
featuresBySymbolizer.push([[], literal]);
}
featuresBySymbolizer[uniqueLiterals[key]][0].push(feature);
}
}
return featuresBySymbolizer;
};
/**
* @param {Object|Element|Document|string} data Feature data.
* @param {ol.parser.Parser} parser Feature parser.
* @param {ol.Projection} projection This sucks. The layer should be a view in
* one projection.
*/
ol.layer.Vector.prototype.parseFeatures = function(data, parser, projection) {
var features;
var lookup = {
'point': this.pointVertices_,
'linestring': this.lineVertices_,
'polygon': this.polygonVertices_,
'multipoint': this.pointVertices_,
'multilinstring': this.lineVertices_,
'multipolygon': this.polygonVertices_
};
var callback = function(feature, type) {
return lookup[type];
};
if (typeof data === 'string') {
goog.asserts.assert(typeof parser.readFeaturesFromString === 'function',
'Expected a parser with readFeaturesFromString method.');
features = parser.readFeaturesFromString(data, {callback: callback});
} else if (typeof data === 'object') {
goog.asserts.assert(typeof parser.readFeaturesFromObject === 'function',
'Expected a parser with a readFeaturesFromObject method.');
features = parser.readFeaturesFromObject(data, {callback: callback});
} else {
// TODO: parse more data types
throw new Error('Data type not supported: ' + data);
}
var sourceProjection = this.getSource().getProjection();
var transform = ol.projection.getTransform(sourceProjection, projection);
transform(
this.pointVertices_.coordinates,
this.pointVertices_.coordinates,
this.pointVertices_.getDimension());
transform(
this.lineVertices_.coordinates,
this.lineVertices_.coordinates,
this.lineVertices_.getDimension());
transform(
this.polygonVertices_.coordinates,
this.polygonVertices_.coordinates,
this.polygonVertices_.getDimension());
this.addFeatures(features);
};
goog.require('ol.filter.Extent');
goog.require('ol.filter.Geometry');
goog.require('ol.filter.Logical');
goog.require('ol.filter.LogicalOperator');
goog.require('ol.geom.GeometryType');
+8
View File
@@ -7,3 +7,11 @@ if (goog.DEBUG) {
var logger = goog.debug.Logger.getLogger('ol');
logger.setLevel(goog.debug.Logger.Level.FINEST);
}
/**
* The CSS class that we'll give the DOM elements to have them unselectable.
*
* @const {string}
*/
ol.CSS_CLASS_UNSELECTABLE = 'ol-unselectable';
+66
View File
@@ -0,0 +1,66 @@
goog.provide('ol.parser.DomFeatureParser');
goog.provide('ol.parser.ObjectFeatureParser');
goog.provide('ol.parser.ReadFeaturesOptions');
goog.provide('ol.parser.StringFeatureParser');
goog.require('ol.Feature');
/**
* @interface
*/
ol.parser.DomFeatureParser = function() {};
/**
* @param {Element|Document} node Document or element node.
* @param {ol.parser.ReadFeaturesOptions=} opt_options Feature reading options.
* @return {Array.<ol.Feature>} Array of features.
*/
ol.parser.DomFeatureParser.prototype.readFeaturesFromNode =
goog.abstractMethod;
/**
* @interface
*/
ol.parser.ObjectFeatureParser = function() {};
/**
* @param {Object} obj Object representing features.
* @param {ol.parser.ReadFeaturesOptions=} opt_options Feature reading options.
* @return {Array.<ol.Feature>} Array of features.
*/
ol.parser.ObjectFeatureParser.prototype.readFeaturesFromObject =
goog.abstractMethod;
/**
* @interface
*/
ol.parser.StringFeatureParser = function() {};
/**
* @param {string} data String data.
* @param {ol.parser.ReadFeaturesOptions=} opt_options Feature reading options.
* @return {Array.<ol.Feature>} Array of features.
*/
ol.parser.StringFeatureParser.prototype.readFeaturesFromString =
goog.abstractMethod;
/**
* @typedef {function(ol.Feature, ol.geom.GeometryType):ol.geom.SharedVertices}
*/
ol.parser.ReadFeaturesCallback;
/**
* @typedef {{callback: ol.parser.ReadFeaturesCallback}}
*/
ol.parser.ReadFeaturesOptions;
+3
View File
@@ -0,0 +1,3 @@
@exportSymbol ol.parser.GeoJSON
@exportProperty ol.parser.GeoJSON.prototype.read
+285
View File
@@ -0,0 +1,285 @@
goog.provide('ol.parser.GeoJSON');
goog.require('ol.Feature');
goog.require('ol.geom.Geometry');
goog.require('ol.geom.GeometryType');
goog.require('ol.geom.LineString');
goog.require('ol.geom.MultiLineString');
goog.require('ol.geom.MultiPoint');
goog.require('ol.geom.MultiPolygon');
goog.require('ol.geom.Point');
goog.require('ol.geom.Polygon');
goog.require('ol.geom.SharedVertices');
goog.require('ol.parser.Parser');
goog.require('ol.parser.ReadFeaturesOptions');
goog.require('ol.parser.StringFeatureParser');
/**
* @constructor
* @implements {ol.parser.StringFeatureParser}
* @extends {ol.parser.Parser}
*/
ol.parser.GeoJSON = function() {};
goog.inherits(ol.parser.GeoJSON, ol.parser.Parser);
/**
* Parse a GeoJSON string.
* @param {string} str GeoJSON string.
* @return {ol.Feature|Array.<ol.Feature>|
* ol.geom.Geometry|Array.<ol.geom.Geometry>} Parsed geometry or array
* of geometries.
*/
ol.parser.GeoJSON.prototype.read = function(str) {
var json = /** @type {GeoJSONObject} */ (JSON.parse(str));
return this.parse_(json);
};
/**
* Parse a GeoJSON feature collection.
* @param {string} str GeoJSON feature collection.
* @param {ol.parser.ReadFeaturesOptions=} opt_options Reader options.
* @return {Array.<ol.Feature>} Array of features.
*/
ol.parser.GeoJSON.prototype.readFeaturesFromString =
function(str, opt_options) {
var json = /** @type {GeoJSONFeatureCollection} */ (JSON.parse(str));
return this.parseFeatureCollection_(json, opt_options);
};
/**
* Parse a GeoJSON feature collection from decoded JSON.
* @param {GeoJSONFeatureCollection} object GeoJSON feature collection decoded
* from JSON.
* @param {ol.parser.ReadFeaturesOptions=} opt_options Reader options.
* @return {Array.<ol.Feature>} Array of features.
*/
ol.parser.GeoJSON.prototype.readFeaturesFromObject =
function(object, opt_options) {
return this.parseFeatureCollection_(object, opt_options);
};
/**
* @param {GeoJSONObject} json GeoJSON object.
* @return {ol.Feature|Array.<ol.Feature>|
* ol.geom.Geometry|Array.<ol.geom.Geometry>} Parsed geometry or array
* of geometries.
* @private
*/
ol.parser.GeoJSON.prototype.parse_ = function(json) {
var result;
switch (json.type) {
case 'FeatureCollection':
result = this.parseFeatureCollection_(
/** @type {GeoJSONFeatureCollection} */ (json));
break;
case 'Feature':
result = this.parseFeature_(
/** @type {GeoJSONFeature} */ (json));
break;
case 'GeometryCollection':
result = this.parseGeometryCollection_(
/** @type {GeoJSONGeometryCollection} */ (json));
break;
case 'Point':
result = this.parsePoint_(
/** @type {GeoJSONGeometry} */ (json));
break;
case 'LineString':
result = this.parseLineString_(
/** @type {GeoJSONGeometry} */ (json));
break;
case 'Polygon':
result = this.parsePolygon_(
/** @type {GeoJSONGeometry} */ (json));
break;
case 'MultiPoint':
result = this.parseMultiPoint_(
/** @type {GeoJSONGeometry} */ (json));
break;
case 'MultiLineString':
result = this.parseMultiLineString_(
/** @type {GeoJSONGeometry} */ (json));
break;
case 'MultiPolygon':
result = this.parseMultiPolygon_(
/** @type {GeoJSONGeometry} */ (json));
break;
default:
throw new Error('GeoJSON parsing not implemented for type: ' + json.type);
}
return result;
};
/**
* @param {GeoJSONFeature} json GeoJSON feature.
* @param {ol.parser.ReadFeaturesOptions=} opt_options Read options.
* @return {ol.Feature} Parsed feature.
* @private
*/
ol.parser.GeoJSON.prototype.parseFeature_ = function(json, opt_options) {
var geomJson = json.geometry,
geometry = null,
options = opt_options || {};
var feature = new ol.Feature(json.properties);
if (geomJson) {
var type = geomJson.type;
var callback = options.callback;
var sharedVertices;
if (callback) {
goog.asserts.assert(type in ol.parser.GeoJSON.GeometryType,
'Bad geometry type: ' + type);
sharedVertices = callback(feature, ol.parser.GeoJSON.GeometryType[type]);
}
switch (type) {
case 'Point':
geometry = this.parsePoint_(geomJson, sharedVertices);
break;
case 'LineString':
geometry = this.parseLineString_(geomJson, sharedVertices);
break;
case 'Polygon':
geometry = this.parsePolygon_(geomJson, sharedVertices);
break;
case 'MultiPoint':
geometry = this.parseMultiPoint_(geomJson, sharedVertices);
break;
case 'MultiLineString':
geometry = this.parseMultiLineString_(geomJson, sharedVertices);
break;
case 'MultiPolygon':
geometry = this.parseMultiPolygon_(geomJson, sharedVertices);
break;
default:
throw new Error('Bad geometry type: ' + type);
}
feature.setGeometry(geometry);
}
return feature;
};
/**
* @param {GeoJSONFeatureCollection} json GeoJSON feature collection.
* @param {ol.parser.ReadFeaturesOptions=} opt_options Read options.
* @return {Array.<ol.Feature>} Parsed array of features.
* @private
*/
ol.parser.GeoJSON.prototype.parseFeatureCollection_ = function(
json, opt_options) {
var features = json.features,
len = features.length,
result = new Array(len),
i;
for (i = 0; i < len; ++i) {
result[i] = this.parseFeature_(
/** @type {GeoJSONFeature} */ (features[i]), opt_options);
}
return result;
};
/**
* @param {GeoJSONGeometryCollection} json GeoJSON geometry collection.
* @return {Array.<ol.geom.Geometry>} Parsed array of geometries.
* @private
*/
ol.parser.GeoJSON.prototype.parseGeometryCollection_ = function(json) {
var geometries = json.geometries,
len = geometries.length,
result = new Array(len),
i;
for (i = 0; i < len; ++i) {
result[i] = this.parse_(/** @type {GeoJSONGeometry} */ (geometries[i]));
}
return result;
};
/**
* @param {GeoJSONGeometry} json GeoJSON linestring.
* @param {ol.geom.SharedVertices=} opt_vertices Shared vertices.
* @return {ol.geom.LineString} Parsed linestring.
* @private
*/
ol.parser.GeoJSON.prototype.parseLineString_ = function(json, opt_vertices) {
return new ol.geom.LineString(json.coordinates, opt_vertices);
};
/**
* @param {GeoJSONGeometry} json GeoJSON multi-linestring.
* @param {ol.geom.SharedVertices=} opt_vertices Shared vertices.
* @return {ol.geom.MultiLineString} Parsed multi-linestring.
* @private
*/
ol.parser.GeoJSON.prototype.parseMultiLineString_ = function(
json, opt_vertices) {
return new ol.geom.MultiLineString(json.coordinates, opt_vertices);
};
/**
* @param {GeoJSONGeometry} json GeoJSON multi-point.
* @param {ol.geom.SharedVertices=} opt_vertices Shared vertices.
* @return {ol.geom.MultiPoint} Parsed multi-point.
* @private
*/
ol.parser.GeoJSON.prototype.parseMultiPoint_ = function(json, opt_vertices) {
return new ol.geom.MultiPoint(json.coordinates, opt_vertices);
};
/**
* @param {GeoJSONGeometry} json GeoJSON multi-polygon.
* @param {ol.geom.SharedVertices=} opt_vertices Shared vertices.
* @return {ol.geom.MultiPolygon} Parsed multi-polygon.
* @private
*/
ol.parser.GeoJSON.prototype.parseMultiPolygon_ = function(json, opt_vertices) {
return new ol.geom.MultiPolygon(json.coordinates, opt_vertices);
};
/**
* @param {GeoJSONGeometry} json GeoJSON point.
* @param {ol.geom.SharedVertices=} opt_vertices Shared vertices.
* @return {ol.geom.Point} Parsed point.
* @private
*/
ol.parser.GeoJSON.prototype.parsePoint_ = function(json, opt_vertices) {
return new ol.geom.Point(json.coordinates, opt_vertices);
};
/**
* @param {GeoJSONGeometry} json GeoJSON polygon.
* @param {ol.geom.SharedVertices=} opt_vertices Shared vertices.
* @return {ol.geom.Polygon} Parsed polygon.
* @private
*/
ol.parser.GeoJSON.prototype.parsePolygon_ = function(json, opt_vertices) {
return new ol.geom.Polygon(json.coordinates, opt_vertices);
};
/**
* @enum {ol.geom.GeometryType}
*/
ol.parser.GeoJSON.GeometryType = {
'Point': ol.geom.GeometryType.POINT,
'LineString': ol.geom.GeometryType.LINESTRING,
'Polygon': ol.geom.GeometryType.POLYGON,
'MultiPoint': ol.geom.GeometryType.MULTIPOINT,
'MultiLineString': ol.geom.GeometryType.MULTILINESTRING,
'MultiPolygon': ol.geom.GeometryType.MULTIPOLYGON,
'GeometryCollection': ol.geom.GeometryType.GEOMETRYCOLLECTION
};
+8
View File
@@ -0,0 +1,8 @@
goog.provide('ol.parser.Parser');
/**
* @constructor
*/
ol.parser.Parser = function() {};
+335
View File
@@ -0,0 +1,335 @@
goog.provide('ol.parser.polyline');
/**
* Encode a list of coordinates in a flat array and return an encoded string
*
* Attention: This function will modify the passed array!
*
* @param {Array.<number>} flatPoints A flat array of coordinates.
* @param {number=} opt_dimension The dimension of the coordinates in the array.
* @return {string} The encoded string.
*/
ol.parser.polyline.encodeFlatCoordinates =
function(flatPoints, opt_dimension) {
var dimension = opt_dimension || 2;
return ol.parser.polyline.encodeDeltas(flatPoints, dimension);
};
/**
* Decode a list of coordinates from an encoded string into a flat array
*
* @param {string} encoded An encoded string.
* @param {number=} opt_dimension The dimension of the coordinates in the
* encoded string.
* @return {Array.<number>} A flat array of coordinates.
*/
ol.parser.polyline.decodeFlatCoordinates = function(encoded, opt_dimension) {
var dimension = opt_dimension || 2;
return ol.parser.polyline.decodeDeltas(encoded, dimension);
};
/**
* Encode a list of n-dimensional points and return an encoded string
*
* Attention: This function will modify the passed array!
*
* @param {Array.<number>} numbers A list of n-dimensional points.
* @param {number} dimension The dimension of the points in the list.
* @param {number=} opt_factor The factor by which the numbers will be
* multiplied. The remaining decimal places will get rounded away.
* @return {string} The encoded string.
*/
ol.parser.polyline.encodeDeltas = function(numbers, dimension, opt_factor) {
var factor = opt_factor || 1e5;
var d;
var lastNumbers = new Array(dimension);
for (d = 0; d < dimension; ++d) {
lastNumbers[d] = 0;
}
var numbersLength = numbers.length;
for (var i = 0; i < numbersLength;) {
for (d = 0; d < dimension; ++d, ++i) {
var num = numbers[i];
var delta = num - lastNumbers[d];
lastNumbers[d] = num;
numbers[i] = delta;
}
}
return ol.parser.polyline.encodeFloats(numbers, factor);
};
/**
* Decode a list of n-dimensional points from an encoded string
*
* @param {string} encoded An encoded string.
* @param {number} dimension The dimension of the points in the encoded string.
* @param {number=} opt_factor The factor by which the resulting numbers will
* be divided.
* @return {Array.<number>} A list of n-dimensional points.
*/
ol.parser.polyline.decodeDeltas = function(encoded, dimension, opt_factor) {
var factor = opt_factor || 1e5;
var d;
var lastNumbers = new Array(dimension);
for (d = 0; d < dimension; ++d) {
lastNumbers[d] = 0;
}
var numbers = ol.parser.polyline.decodeFloats(encoded, factor);
var numbersLength = numbers.length;
for (var i = 0; i < numbersLength;) {
for (d = 0; d < dimension; ++d, ++i) {
lastNumbers[d] += numbers[i];
numbers[i] = lastNumbers[d];
}
}
return numbers;
};
/**
* Encode a list of floating point numbers and return an encoded string
*
* Attention: This function will modify the passed array!
*
* @param {Array.<number>} numbers A list of floating point numbers.
* @param {number=} opt_factor The factor by which the numbers will be
* multiplied. The remaining decimal places will get rounded away.
* @return {string} The encoded string.
*/
ol.parser.polyline.encodeFloats = function(numbers, opt_factor) {
var factor = opt_factor || 1e5;
var numbersLength = numbers.length;
for (var i = 0; i < numbersLength; ++i) {
numbers[i] = Math.round(numbers[i] * factor);
}
return ol.parser.polyline.encodeSignedIntegers(numbers);
};
/**
* Decode a list of floating point numbers from an encoded string
*
* @param {string} encoded An encoded string.
* @param {number=} opt_factor The factor by which the result will be divided.
* @return {Array.<number>} A list of floating point numbers.
*/
ol.parser.polyline.decodeFloats = function(encoded, opt_factor) {
var factor = opt_factor || 1e5;
var numbers = ol.parser.polyline.decodeSignedIntegers(encoded);
var numbersLength = numbers.length;
for (var i = 0; i < numbersLength; ++i) {
numbers[i] /= factor;
}
return numbers;
};
/**
* Encode a list of signed integers and return an encoded string
*
* Attention: This function will modify the passed array!
*
* @param {Array.<number>} numbers A list of signed integers.
* @return {string} The encoded string.
*/
ol.parser.polyline.encodeSignedIntegers = function(numbers) {
var numbersLength = numbers.length;
for (var i = 0; i < numbersLength; ++i) {
var num = numbers[i];
var signedNum = num << 1;
if (num < 0) {
signedNum = ~(signedNum);
}
numbers[i] = signedNum;
}
return ol.parser.polyline.encodeUnsignedIntegers(numbers);
};
/**
* Decode a list of signed integers from an encoded string
*
* @param {string} encoded An encoded string.
* @return {Array.<number>} A list of signed integers.
*/
ol.parser.polyline.decodeSignedIntegers = function(encoded) {
var numbers = ol.parser.polyline.decodeUnsignedIntegers(encoded);
var numbersLength = numbers.length;
for (var i = 0; i < numbersLength; ++i) {
var num = numbers[i];
numbers[i] = (num & 1) ? ~(num >> 1) : (num >> 1);
}
return numbers;
};
/**
* Encode a list of unsigned integers and return an encoded string
*
* @param {Array.<number>} numbers A list of unsigned integers.
* @return {string} The encoded string.
*/
ol.parser.polyline.encodeUnsignedIntegers = function(numbers) {
var encoded = '';
var numbersLength = numbers.length;
for (var i = 0; i < numbersLength; ++i) {
encoded += ol.parser.polyline.encodeUnsignedInteger(numbers[i]);
}
return encoded;
};
/**
* Decode a list of unsigned integers from an encoded string
*
* @param {string} encoded An encoded string.
* @return {Array.<number>} A list of unsigned integers.
*/
ol.parser.polyline.decodeUnsignedIntegers = function(encoded) {
var numbers = [];
var current = 0;
var shift = 0;
var encodedLength = encoded.length;
for (var i = 0; i < encodedLength; ++i) {
var b = encoded.charCodeAt(i) - 63;
current |= (b & 0x1f) << shift;
if (b < 0x20) {
numbers.push(current);
current = 0;
shift = 0;
} else {
shift += 5;
}
}
return numbers;
};
/**
* Encode one single floating point number and return an encoded string
*
* @param {number} num Floating point number that should be encoded.
* @param {number=} opt_factor The factor by which num will be multiplied.
* The remaining decimal places will get rounded away.
* @return {string} The encoded string.
*/
ol.parser.polyline.encodeFloat = function(num, opt_factor) {
num = Math.round(num * (opt_factor || 1e5));
return ol.parser.polyline.encodeSignedInteger(num);
};
/**
* Decode one single floating point number from an encoded string
*
* @param {string} encoded An encoded string.
* @param {number=} opt_factor The factor by which the result will be divided.
* @return {number} The decoded floating point number.
*/
ol.parser.polyline.decodeFloat = function(encoded, opt_factor) {
var result = ol.parser.polyline.decodeSignedInteger(encoded);
return result / (opt_factor || 1e5);
};
/**
* Encode one single signed integer and return an encoded string
*
* @param {number} num Signed integer that should be encoded.
* @return {string} The encoded string.
*/
ol.parser.polyline.encodeSignedInteger = function(num) {
var signedNum = num << 1;
if (num < 0) {
signedNum = ~(signedNum);
}
return ol.parser.polyline.encodeUnsignedInteger(signedNum);
};
/**
* Decode one single signed integer from an encoded string
*
* @param {string} encoded An encoded string.
* @return {number} The decoded signed integer.
*/
ol.parser.polyline.decodeSignedInteger = function(encoded) {
var result = ol.parser.polyline.decodeUnsignedInteger(encoded);
return ((result & 1) ? ~(result >> 1) : (result >> 1));
};
/**
* Encode one single unsigned integer and return an encoded string
*
* @param {number} num Unsigned integer that should be encoded.
* @return {string} The encoded string.
*/
ol.parser.polyline.encodeUnsignedInteger = function(num) {
var value, encoded = '';
while (num >= 0x20) {
value = (0x20 | (num & 0x1f)) + 63;
encoded += (String.fromCharCode(value));
num >>= 5;
}
value = num + 63;
encoded += (String.fromCharCode(value));
return encoded;
};
/**
* Decode one single unsigned integer from an encoded string
*
* @param {string} encoded An encoded string.
* @return {number} The decoded unsigned integer.
*/
ol.parser.polyline.decodeUnsignedInteger = function(encoded) {
var result = 0;
var shift = 0;
var encodedLength = encoded.length;
for (var i = 0; i < encodedLength; ++i) {
var b = encoded.charCodeAt(i) - 63;
result |= (b & 0x1f) << shift;
if (b < 0x20)
break;
shift += 5;
}
return result;
};
+4
View File
@@ -1,9 +1,12 @@
goog.provide('ol.parser.XML');
goog.require('ol.parser.Parser');
/**
* @constructor
* @extends {ol.parser.Parser}
*/
ol.parser.XML = function() {
this.regExes = {
@@ -13,6 +16,7 @@ ol.parser.XML = function() {
trimComma: (/\s*,\s*/g)
};
};
goog.inherits(ol.parser.XML, ol.parser.Parser);
/**
@@ -6,12 +6,15 @@ goog.require('goog.array');
goog.require('goog.dom');
goog.require('goog.style');
goog.require('goog.vec.Mat4');
goog.require('ol');
goog.require('ol.Size');
goog.require('ol.layer.ImageLayer');
goog.require('ol.layer.TileLayer');
goog.require('ol.layer.Vector');
goog.require('ol.renderer.Map');
goog.require('ol.renderer.canvas.ImageLayer');
goog.require('ol.renderer.canvas.TileLayer');
goog.require('ol.renderer.canvas.VectorLayer');
@@ -38,7 +41,7 @@ ol.renderer.canvas.Map = function(container, map) {
this.canvas_ = goog.dom.createElement(goog.dom.TagName.CANVAS);
this.canvas_.height = this.canvasSize_.height;
this.canvas_.width = this.canvasSize_.width;
this.canvas_.className = 'ol-unselectable';
this.canvas_.className = ol.CSS_CLASS_UNSELECTABLE;
goog.dom.insertChildAt(container, this.canvas_, 0);
/**
@@ -65,6 +68,8 @@ ol.renderer.canvas.Map.prototype.createLayerRenderer = function(layer) {
return new ol.renderer.canvas.ImageLayer(this, layer);
} else if (layer instanceof ol.layer.TileLayer) {
return new ol.renderer.canvas.TileLayer(this, layer);
} else if (layer instanceof ol.layer.Vector) {
return new ol.renderer.canvas.VectorLayer(this, layer);
} else {
goog.asserts.assert(false);
return null;
@@ -110,6 +115,8 @@ ol.renderer.canvas.Map.prototype.renderFrame = function(frameState) {
context.globalAlpha = 1;
context.fillRect(0, 0, size.width, size.height);
this.calculateMatrices2D(frameState);
goog.array.forEach(frameState.layersArray, function(layer) {
var layerState = frameState.layerStates[goog.getUid(layer)];
@@ -144,6 +151,4 @@ ol.renderer.canvas.Map.prototype.renderFrame = function(frameState) {
this.renderedVisible_ = true;
}
this.calculateMatrices2D(frameState);
};
@@ -0,0 +1,404 @@
goog.provide('ol.renderer.canvas.VectorLayer');
goog.require('goog.vec.Mat4');
goog.require('ol.Extent');
goog.require('ol.Size');
goog.require('ol.TileCache');
goog.require('ol.TileCoord');
goog.require('ol.ViewHint');
goog.require('ol.filter.Extent');
goog.require('ol.filter.Geometry');
goog.require('ol.filter.Logical');
goog.require('ol.filter.LogicalOperator');
goog.require('ol.geom.GeometryType');
goog.require('ol.layer.Vector');
goog.require('ol.renderer.canvas.Layer');
goog.require('ol.renderer.canvas.VectorRenderer');
goog.require('ol.tilegrid.TileGrid');
/**
* @constructor
* @extends {ol.renderer.canvas.Layer}
* @param {ol.renderer.Map} mapRenderer Map renderer.
* @param {ol.layer.Vector} layer Vector layer.
*/
ol.renderer.canvas.VectorLayer = function(mapRenderer, layer) {
goog.base(this, mapRenderer, layer);
/**
* Final canvas made available to the map renderer.
* @private
* @type {HTMLCanvasElement}
*/
this.canvas_ = /** @type {HTMLCanvasElement} */
(goog.dom.createElement(goog.dom.TagName.CANVAS));
/**
* @private
* @type {CanvasRenderingContext2D}
*/
this.context_ = /** @type {CanvasRenderingContext2D} */
(this.canvas_.getContext('2d'));
/**
* @private
* @type {!goog.vec.Mat4.Number}
*/
this.transform_ = goog.vec.Mat4.createNumber();
/**
* Interim canvas for drawing newly visible features.
* @private
* @type {HTMLCanvasElement}
*/
this.sketchCanvas_ = /** @type {HTMLCanvasElement} */
(goog.dom.createElement(goog.dom.TagName.CANVAS));
/**
* @private
* @type {!goog.vec.Mat4.Number}
*/
this.sketchTransform_ = goog.vec.Mat4.createNumber();
/**
* @private
* @type {ol.TileCache}
*/
this.tileCache_ = new ol.TileCache(
ol.renderer.canvas.VectorLayer.TILECACHE_SIZE);
// TODO: this is far too coarse, we want extent of added features
goog.events.listenOnce(layer, goog.events.EventType.CHANGE,
this.handleLayerChange_, false, this);
/**
* @private
* @type {HTMLCanvasElement}
*/
this.tileArchetype_ = null;
/**
* Geometry filters in rendering order.
* @private
* @type {Array.<ol.filter.Geometry>}
* TODO: these will go away shortly (in favor of one call per symbolizer type)
*/
this.geometryFilters_ = [
new ol.filter.Geometry(ol.geom.GeometryType.POINT),
new ol.filter.Geometry(ol.geom.GeometryType.MULTIPOINT),
new ol.filter.Geometry(ol.geom.GeometryType.LINESTRING),
new ol.filter.Geometry(ol.geom.GeometryType.MULTILINESTRING),
new ol.filter.Geometry(ol.geom.GeometryType.POLYGON),
new ol.filter.Geometry(ol.geom.GeometryType.MULTIPOLYGON)
];
/**
* @private
* @type {number}
*/
this.renderedResolution_;
/**
* @private
* @type {ol.Extent}
*/
this.renderedExtent_ = null;
/**
* Flag to be set internally when we know something has changed that suggests
* we need to re-render.
* TODO: discuss setting this for all layers when something changes before
* calling map.render().
* @private
* @type {boolean}
*/
this.dirty_ = false;
/**
* @private
* @type {boolean}
*/
this.pendingCachePrune_ = false;
/**
* Grid used for internal generation of canvas tiles. This is created
* lazily so we have access to the view projection.
*
* @private
* @type {ol.tilegrid.TileGrid}
*/
this.tileGrid_ = null;
/**
* @private
* @type {function()}
*/
this.requestMapRenderFrame_ = goog.bind(function() {
this.dirty_ = true;
mapRenderer.getMap().requestRenderFrame();
}, this);
};
goog.inherits(ol.renderer.canvas.VectorLayer, ol.renderer.canvas.Layer);
/**
* Get rid cached tiles. If the optional extent is provided, only tiles that
* intersect that extent will be removed.
* @param {ol.Extent=} opt_extent extent Expire tiles within this extent only.
* @private
*/
ol.renderer.canvas.VectorLayer.prototype.expireTiles_ = function(opt_extent) {
if (goog.isDef(opt_extent)) {
// TODO: implement this
}
this.tileCache_.clear();
};
/**
* @inheritDoc
*/
ol.renderer.canvas.VectorLayer.prototype.getImage = function() {
return this.canvas_;
};
/**
* @return {ol.layer.Vector} Vector layer.
*/
ol.renderer.canvas.VectorLayer.prototype.getVectorLayer = function() {
return /** @type {ol.layer.Vector} */ (this.getLayer());
};
/**
* @inheritDoc
*/
ol.renderer.canvas.VectorLayer.prototype.getTransform = function() {
return this.transform_;
};
/**
* @param {goog.events.Event} event Layer change event.
* @private
*/
ol.renderer.canvas.VectorLayer.prototype.handleLayerChange_ = function(event) {
// TODO: get rid of this in favor of vector specific events
this.expireTiles_();
this.requestMapRenderFrame_();
};
/**
* @inheritDoc
*/
ol.renderer.canvas.VectorLayer.prototype.renderFrame =
function(frameState, layerState) {
// TODO: consider bailing out here if rendered center and resolution
// have not changed. Requires that other change listeners set a dirty flag.
var view2DState = frameState.view2DState,
resolution = view2DState.resolution,
extent = frameState.extent,
layer = this.getVectorLayer(),
tileGrid = this.tileGrid_;
if (goog.isNull(tileGrid)) {
// lazy tile grid creation to match the view projection
tileGrid = ol.tilegrid.createForProjection(
view2DState.projection,
22, // should be no harm in going big here - ideally, it would be ∞
new ol.Size(512, 512));
this.tileGrid_ = tileGrid;
}
// set up transform for the layer canvas to be drawn to the map canvas
var z = tileGrid.getZForResolution(resolution),
tileResolution = tileGrid.getResolution(z),
tileRange = tileGrid.getTileRangeForExtentAndResolution(
extent, tileResolution),
tileRangeExtent = tileGrid.getTileRangeExtent(z, tileRange),
tileSize = tileGrid.getTileSize(z),
sketchOrigin = tileRangeExtent.getTopLeft(),
transform = this.transform_;
goog.vec.Mat4.makeIdentity(transform);
goog.vec.Mat4.translate(transform,
frameState.size.width / 2,
frameState.size.height / 2,
0);
goog.vec.Mat4.scale(transform,
tileResolution / resolution, tileResolution / resolution, 1);
goog.vec.Mat4.rotateZ(transform, view2DState.rotation);
goog.vec.Mat4.translate(transform,
(sketchOrigin.x - view2DState.center.x) / tileResolution,
(view2DState.center.y - sketchOrigin.y) / tileResolution,
0);
/**
* Fastest path out of here. This method is called many many times while
* there is nothing to do (e.g. while waiting for tiles from every other
* layer to load.) Do not put anything above here that is more expensive than
* necessary. And look for ways to get here faster.
*/
if (!this.dirty_ && this.renderedResolution_ === tileResolution &&
// TODO: extent.equals()
this.renderedExtent_.toString() === tileRangeExtent.toString()) {
return;
}
if (goog.isNull(this.tileArchetype_)) {
this.tileArchetype_ = /** @type {HTMLCanvasElement} */
(goog.dom.createElement(goog.dom.TagName.CANVAS));
this.tileArchetype_.width = tileSize.width;
this.tileArchetype_.height = tileSize.height;
}
/**
* Prepare the sketch canvas. This covers the currently visible tile range
* and will have rendered all newly visible features.
*/
var sketchCanvas = this.sketchCanvas_;
var sketchSize = new ol.Size(
tileSize.width * tileRange.getWidth(),
tileSize.height * tileRange.getHeight());
// transform for map coords to sketch canvas pixel coords
var sketchTransform = this.sketchTransform_;
var halfWidth = sketchSize.width / 2;
var halfHeight = sketchSize.height / 2;
goog.vec.Mat4.makeIdentity(sketchTransform);
goog.vec.Mat4.translate(sketchTransform,
halfWidth,
halfHeight,
0);
goog.vec.Mat4.scale(sketchTransform,
1 / tileResolution,
-1 / tileResolution,
1);
goog.vec.Mat4.translate(sketchTransform,
-(sketchOrigin.x + halfWidth * tileResolution),
-(sketchOrigin.y - halfHeight * tileResolution),
0);
// clear/resize sketch canvas
sketchCanvas.width = sketchSize.width;
sketchCanvas.height = sketchSize.height;
var sketchCanvasRenderer = new ol.renderer.canvas.VectorRenderer(
sketchCanvas, sketchTransform, undefined, this.requestMapRenderFrame_);
// clear/resize final canvas
var finalCanvas = this.canvas_;
finalCanvas.width = sketchSize.width;
finalCanvas.height = sketchSize.height;
var finalContext = this.context_;
var featuresToRender = {};
var tilesToRender = {};
var tilesOnSketchCanvas = {};
// TODO make gutter configurable?
var tileGutter = 15 * tileResolution;
var tile, tileCoord, key, tileState, x, y;
// render features by geometry type
var filters = this.geometryFilters_,
numFilters = filters.length,
deferred = false,
i, geomFilter, tileExtent, extentFilter, type,
groups, group, j, numGroups;
for (x = tileRange.minX; x <= tileRange.maxX; ++x) {
for (y = tileRange.minY; y <= tileRange.maxY; ++y) {
tileCoord = new ol.TileCoord(z, x, y);
key = tileCoord.toString();
if (this.tileCache_.containsKey(key)) {
tilesToRender[key] = tileCoord;
} else if (!frameState.viewHints[ol.ViewHint.ANIMATING]) {
tileExtent = tileGrid.getTileCoordExtent(tileCoord);
tileExtent.minX -= tileGutter;
tileExtent.minY -= tileGutter;
tileExtent.maxX += tileGutter;
tileExtent.maxY += tileGutter;
extentFilter = new ol.filter.Extent(tileExtent);
for (i = 0; i < numFilters; ++i) {
geomFilter = filters[i];
type = geomFilter.getType();
if (!goog.isDef(featuresToRender[type])) {
featuresToRender[type] = {};
}
goog.object.extend(featuresToRender[type],
layer.getFeaturesObject(new ol.filter.Logical(
[geomFilter, extentFilter], ol.filter.LogicalOperator.AND)));
}
tilesOnSketchCanvas[key] = tileCoord;
}
}
}
for (type in featuresToRender) {
groups = layer.groupFeaturesBySymbolizerLiteral(featuresToRender[type]);
numGroups = groups.length;
for (j = 0; j < numGroups; ++j) {
group = groups[j];
deferred = sketchCanvasRenderer.renderFeaturesByGeometryType(
/** @type {ol.geom.GeometryType} */ (type),
group[0], group[1]);
if (deferred) {
break;
}
}
if (!deferred) {
goog.object.extend(tilesToRender, tilesOnSketchCanvas);
}
}
this.dirty_ = true;
for (key in tilesToRender) {
tileCoord = tilesToRender[key];
if (this.tileCache_.containsKey(key)) {
tile = /** @type {HTMLCanvasElement} */ (this.tileCache_.get(key));
} else {
tile = /** @type {HTMLCanvasElement} */
(this.tileArchetype_.cloneNode(false));
tile.getContext('2d').drawImage(sketchCanvas,
(tileRange.minX - tileCoord.x) * tileSize.width,
(tileCoord.y - tileRange.maxY) * tileSize.height);
this.tileCache_.set(key, tile);
}
finalContext.drawImage(tile,
tileSize.width * (tileCoord.x - tileRange.minX),
tileSize.height * (tileRange.maxY - tileCoord.y));
this.dirty_ = false;
}
this.renderedResolution_ = tileResolution;
this.renderedExtent_ = tileRangeExtent;
if (!this.pendingCachePrune_) {
this.pendingCachePrune_ = true;
frameState.postRenderFunctions.push(goog.bind(this.pruneTileCache_, this));
}
};
/**
* Get rid of tiles that exceed the cache capacity.
* TODO: add a method to the cache to handle this
* @private
*/
ol.renderer.canvas.VectorLayer.prototype.pruneTileCache_ = function() {
while (this.tileCache_.canExpireCache()) {
this.tileCache_.pop();
}
this.pendingCachePrune_ = false;
};
/**
* @type {number}
*/
ol.renderer.canvas.VectorLayer.TILECACHE_SIZE = 128;
@@ -0,0 +1,439 @@
goog.provide('ol.renderer.canvas.VectorRenderer');
goog.require('goog.asserts');
goog.require('goog.vec.Mat4');
goog.require('ol.Feature');
goog.require('ol.Pixel');
goog.require('ol.geom.Geometry');
goog.require('ol.geom.GeometryType');
goog.require('ol.geom.LineString');
goog.require('ol.geom.MultiLineString');
goog.require('ol.geom.MultiPoint');
goog.require('ol.geom.MultiPolygon');
goog.require('ol.geom.Point');
goog.require('ol.geom.Polygon');
goog.require('ol.style.IconLiteral');
goog.require('ol.style.LineLiteral');
goog.require('ol.style.PointLiteral');
goog.require('ol.style.PolygonLiteral');
goog.require('ol.style.ShapeLiteral');
goog.require('ol.style.ShapeType');
goog.require('ol.style.SymbolizerLiteral');
/**
* @constructor
* @param {HTMLCanvasElement} canvas Target canvas.
* @param {goog.vec.Mat4.Number} transform Transform.
* @param {ol.Pixel=} opt_offset Pixel offset for top-left corner. This is
* provided as an optional argument as a convenience in cases where the
* transform applies to a separate canvas.
* @param {function()=} opt_iconLoadedCallback Callback for deferred rendering
* when images need to be loaded before rendering.
*/
ol.renderer.canvas.VectorRenderer =
function(canvas, transform, opt_offset, opt_iconLoadedCallback) {
var context = /** @type {CanvasRenderingContext2D} */
(canvas.getContext('2d')),
dx = goog.isDef(opt_offset) ? opt_offset.x : 0,
dy = goog.isDef(opt_offset) ? opt_offset.y : 0;
/**
* @type {goog.vec.Mat4.Number}
* @private
*/
this.transform_ = transform;
context.setTransform(
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) + dx,
goog.vec.Mat4.getElement(transform, 1, 3) + dy);
var vec = [1, 0, 0];
goog.vec.Mat4.multVec3NoTranslate(transform, vec, vec);
/**
* @type {number}
* @private
*/
this.inverseScale_ = 1 / Math.sqrt(vec[0] * vec[0] + vec[1] * vec[1]);
/**
* @type {CanvasRenderingContext2D}
* @private
*/
this.context_ = context;
/**
* @type {function()|undefined}
* @private
*/
this.iconLoadedCallback_ = opt_iconLoadedCallback;
};
/**
* @param {ol.geom.GeometryType} type Geometry type.
* @param {Array.<ol.Feature>} features Array of features.
* @param {ol.style.SymbolizerLiteral} symbolizer Symbolizer.
* @return {boolean} true if deferred, false if rendered.
*/
ol.renderer.canvas.VectorRenderer.prototype.renderFeaturesByGeometryType =
function(type, features, symbolizer) {
var deferred = false;
switch (type) {
case ol.geom.GeometryType.POINT:
case ol.geom.GeometryType.MULTIPOINT:
goog.asserts.assert(symbolizer instanceof ol.style.PointLiteral,
'Expected point symbolizer: ' + symbolizer);
deferred = this.renderPointFeatures_(
features, /** @type {ol.style.PointLiteral} */ (symbolizer));
break;
case ol.geom.GeometryType.LINESTRING:
case ol.geom.GeometryType.MULTILINESTRING:
goog.asserts.assert(symbolizer instanceof ol.style.LineLiteral,
'Expected line symbolizer: ' + symbolizer);
this.renderLineStringFeatures_(
features, /** @type {ol.style.LineLiteral} */ (symbolizer));
break;
case ol.geom.GeometryType.POLYGON:
case ol.geom.GeometryType.MULTIPOLYGON:
goog.asserts.assert(symbolizer instanceof ol.style.PolygonLiteral,
'Expected polygon symbolizer: ' + symbolizer);
this.renderPolygonFeatures_(
features, /** @type {ol.style.PolygonLiteral} */ (symbolizer));
break;
default:
throw new Error('Rendering not implemented for geometry type: ' + type);
}
return deferred;
};
/**
* @param {Array.<ol.Feature>} features Array of line features.
* @param {ol.style.LineLiteral} symbolizer Line symbolizer.
* @private
*/
ol.renderer.canvas.VectorRenderer.prototype.renderLineStringFeatures_ =
function(features, symbolizer) {
var context = this.context_,
i, ii, geometry, components, j, jj, line, dim, k, kk, x, y;
context.globalAlpha = symbolizer.opacity;
context.strokeStyle = symbolizer.strokeColor;
context.lineWidth = symbolizer.strokeWidth * this.inverseScale_;
context.lineCap = 'round'; // TODO: accept this as a symbolizer property
context.lineJoin = 'round'; // TODO: accept this as a symbolizer property
context.beginPath();
for (i = 0, ii = features.length; i < ii; ++i) {
geometry = features[i].getGeometry();
if (geometry instanceof ol.geom.LineString) {
components = [geometry];
} else {
goog.asserts.assert(geometry instanceof ol.geom.MultiLineString,
'Expected MultiLineString');
components = geometry.components;
}
for (j = 0, jj = components.length; j < jj; ++j) {
line = components[j];
dim = line.dimension;
for (k = 0, kk = line.getCount(); k < kk; ++k) {
x = line.get(k, 0);
y = line.get(k, 1);
if (k === 0) {
context.moveTo(x, y);
} else {
context.lineTo(x, y);
}
}
}
}
context.stroke();
};
/**
* @param {Array.<ol.Feature>} features Array of point features.
* @param {ol.style.PointLiteral} symbolizer Point symbolizer.
* @return {boolean} true if deferred, false if rendered.
* @private
*/
ol.renderer.canvas.VectorRenderer.prototype.renderPointFeatures_ =
function(features, symbolizer) {
var context = this.context_,
content, alpha, i, ii, geometry, components, j, jj, point, vec;
if (symbolizer instanceof ol.style.ShapeLiteral) {
content = ol.renderer.canvas.VectorRenderer.renderShape(symbolizer);
alpha = 1;
} else if (symbolizer instanceof ol.style.IconLiteral) {
content = ol.renderer.canvas.VectorRenderer.renderIcon(
symbolizer, this.iconLoadedCallback_);
alpha = symbolizer.opacity;
} else {
throw new Error('Unsupported symbolizer: ' + symbolizer);
}
if (goog.isNull(content)) {
return true;
}
var midWidth = content.width / 2;
var midHeight = content.height / 2;
context.save();
context.setTransform(1, 0, 0, 1, -midWidth, -midHeight);
context.globalAlpha = alpha;
for (i = 0, ii = features.length; i < ii; ++i) {
geometry = features[i].getGeometry();
if (geometry instanceof ol.geom.Point) {
components = [geometry];
} else {
goog.asserts.assert(geometry instanceof ol.geom.MultiPoint,
'Expected MultiPoint');
components = geometry.components;
}
for (j = 0, jj = components.length; j < jj; ++j) {
point = components[j];
vec = goog.vec.Mat4.multVec3(
this.transform_, [point.get(0), point.get(1), 0], []);
context.drawImage(content, vec[0], vec[1], content.width, content.height);
}
}
context.restore();
return false;
};
/**
* @param {Array.<ol.Feature>} features Array of polygon features.
* @param {ol.style.PolygonLiteral} symbolizer Polygon symbolizer.
* @private
*/
ol.renderer.canvas.VectorRenderer.prototype.renderPolygonFeatures_ =
function(features, symbolizer) {
var context = this.context_,
strokeColor = symbolizer.strokeColor,
fillColor = symbolizer.fillColor,
i, ii, geometry, components, j, jj, poly,
rings, numRings, ring, dim, k, kk, x, y;
context.globalAlpha = symbolizer.opacity;
if (strokeColor) {
context.strokeStyle = symbolizer.strokeColor;
context.lineWidth = symbolizer.strokeWidth * this.inverseScale_;
context.lineCap = 'round'; // TODO: accept this as a symbolizer property
context.lineJoin = 'round'; // TODO: accept this as a symbolizer property
}
if (fillColor) {
context.fillStyle = fillColor;
}
/**
* Four scenarios covered here:
* 1) stroke only, no holes - only need to have a single path
* 2) fill only, no holes - only need to have a single path
* 3) fill and stroke, no holes
* 4) holes - render polygon to sketch canvas first
*/
context.beginPath();
for (i = 0, ii = features.length; i < ii; ++i) {
geometry = features[i].getGeometry();
if (geometry instanceof ol.geom.Polygon) {
components = [geometry];
} else {
goog.asserts.assert(geometry instanceof ol.geom.MultiPolygon,
'Expected MultiPolygon');
components = geometry.components;
}
for (j = 0, jj = components.length; j < jj; ++j) {
poly = components[j];
dim = poly.dimension;
rings = poly.rings;
numRings = rings.length;
if (numRings > 0) {
// TODO: scenario 4
ring = rings[0];
for (k = 0, kk = ring.getCount(); k < kk; ++k) {
x = ring.get(k, 0);
y = ring.get(k, 1);
if (k === 0) {
context.moveTo(x, y);
} else {
context.lineTo(x, y);
}
}
if (fillColor && strokeColor) {
// scenario 3 - fill and stroke each time
context.fill();
context.stroke();
if (i < ii - 1 || j < jj - 1) {
context.beginPath();
}
}
}
}
}
if (!(fillColor && strokeColor)) {
if (fillColor) {
// scenario 2 - fill all at once
context.fill();
} else {
// scenario 1 - stroke all at once
context.stroke();
}
}
};
/**
* @param {ol.style.ShapeLiteral} circle Shape symbolizer.
* @return {!HTMLCanvasElement} Canvas element.
* @private
*/
ol.renderer.canvas.VectorRenderer.renderCircle_ = function(circle) {
var strokeWidth = circle.strokeWidth || 0,
size = circle.size + (2 * strokeWidth) + 1,
mid = size / 2,
canvas = /** @type {HTMLCanvasElement} */
(goog.dom.createElement(goog.dom.TagName.CANVAS)),
context = /** @type {CanvasRenderingContext2D} */
(canvas.getContext('2d')),
fillColor = circle.fillColor,
strokeColor = circle.strokeColor,
twoPi = Math.PI * 2;
canvas.height = size;
canvas.width = size;
context.globalAlpha = circle.opacity;
if (fillColor) {
context.fillStyle = fillColor;
}
if (strokeColor) {
context.lineWidth = strokeWidth;
context.strokeStyle = strokeColor;
context.lineCap = 'round'; // TODO: accept this as a symbolizer property
context.lineJoin = 'round'; // TODO: accept this as a symbolizer property
}
context.beginPath();
context.arc(mid, mid, circle.size / 2, 0, twoPi, true);
if (fillColor) {
context.fill();
}
if (strokeColor) {
context.stroke();
}
return canvas;
};
/**
* @param {ol.style.ShapeLiteral} shape Shape symbolizer.
* @return {!HTMLCanvasElement} Canvas element.
*/
ol.renderer.canvas.VectorRenderer.renderShape = function(shape) {
var canvas;
if (shape.type === ol.style.ShapeType.CIRCLE) {
canvas = ol.renderer.canvas.VectorRenderer.renderCircle_(shape);
} else {
throw new Error('Unsupported shape type: ' + shape);
}
return canvas;
};
/**
* @param {ol.style.IconLiteral} icon Icon literal.
* @param {function()=} opt_callback Callback which will be called when
* the icon is loaded and rendering will work without deferring.
* @return {HTMLImageElement} image element of null if deferred.
*/
ol.renderer.canvas.VectorRenderer.renderIcon = function(icon, opt_callback) {
var url = icon.url;
var image = ol.renderer.canvas.VectorRenderer.icons_[url];
var deferred = false;
if (!goog.isDef(image)) {
deferred = true;
image = /** @type {HTMLImageElement} */
(goog.dom.createElement(goog.dom.TagName.IMG));
goog.events.listenOnce(image, goog.events.EventType.ERROR,
goog.bind(ol.renderer.canvas.VectorRenderer.handleIconError_, null,
opt_callback),
false, ol.renderer.canvas.VectorRenderer.renderIcon);
goog.events.listenOnce(image, goog.events.EventType.LOAD,
goog.bind(ol.renderer.canvas.VectorRenderer.handleIconLoad_, null,
opt_callback),
false, ol.renderer.canvas.VectorRenderer.renderIcon);
image.setAttribute('src', url);
ol.renderer.canvas.VectorRenderer.icons_[url] = image;
} else if (!goog.isNull(image)) {
var width = icon.width,
height = icon.height;
if (goog.isDef(width) && goog.isDef(height)) {
image.width = width;
image.height = height;
} else if (goog.isDef(width)) {
image.height = width / image.width * image.height;
image.width = width;
} else if (goog.isDef(height)) {
image.width = height / image.height * image.width;
image.height = height;
}
}
return deferred ? null : image;
};
/**
* @type {Object.<string, HTMLImageElement>}
* @private
*/
ol.renderer.canvas.VectorRenderer.icons_ = {};
/**
* @param {function()=} opt_callback Callback.
* @param {Event=} opt_event Event.
* @private
*/
ol.renderer.canvas.VectorRenderer.handleIconError_ =
function(opt_callback, opt_event) {
if (goog.isDef(opt_event)) {
var url = opt_event.target.getAttribute('src');
ol.renderer.canvas.VectorRenderer.icons_[url] = null;
ol.renderer.canvas.VectorRenderer.handleIconLoad_(opt_callback, opt_event);
}
};
/**
* @param {function()=} opt_callback Callback.
* @param {Event=} opt_event Event.
* @private
*/
ol.renderer.canvas.VectorRenderer.handleIconLoad_ =
function(opt_callback, opt_event) {
if (goog.isDef(opt_event)) {
var url = opt_event.target.getAttribute('src');
ol.renderer.canvas.VectorRenderer.icons_[url] =
/** @type {HTMLImageElement} */ (opt_event.target);
}
if (goog.isDef(opt_callback)) {
opt_callback();
}
};
+2 -10
View File
@@ -5,6 +5,7 @@ goog.require('goog.asserts');
goog.require('goog.dom');
goog.require('goog.dom.TagName');
goog.require('goog.style');
goog.require('ol');
goog.require('ol.layer.ImageLayer');
goog.require('ol.layer.TileLayer');
goog.require('ol.renderer.Map');
@@ -28,7 +29,7 @@ ol.renderer.dom.Map = function(container, map) {
* @private
*/
this.layersPane_ = goog.dom.createElement(goog.dom.TagName.DIV);
this.layersPane_.className = 'ol-layers ol-unselectable';
this.layersPane_.className = 'ol-layers ' + ol.CSS_CLASS_UNSELECTABLE;
var style = this.layersPane_.style;
style.position = 'absolute';
style.width = '100%';
@@ -46,15 +47,6 @@ ol.renderer.dom.Map = function(container, map) {
goog.inherits(ol.renderer.dom.Map, ol.renderer.Map);
/**
* @inheritDoc
*/
ol.renderer.dom.Map.prototype.addLayer = function(layer) {
goog.base(this, 'addLayer', layer);
this.getMap().render();
};
/**
* @inheritDoc
*/
+2
View File
@@ -79,6 +79,7 @@ goog.inherits(ol.renderer.Map, goog.Disposable);
ol.renderer.Map.prototype.addLayer = function(layer) {
var layerRenderer = this.createLayerRenderer(layer);
this.setLayerRenderer(layer, layerRenderer);
this.getMap().render();
};
@@ -224,6 +225,7 @@ ol.renderer.Map.prototype.handleLayersRemove = function(collectionEvent) {
*/
ol.renderer.Map.prototype.removeLayer = function(layer) {
goog.dispose(this.removeLayerRenderer(layer));
this.getMap().render();
};
@@ -11,6 +11,7 @@ goog.require('goog.events');
goog.require('goog.events.Event');
goog.require('goog.style');
goog.require('goog.webgl');
goog.require('ol');
goog.require('ol.FrameState');
goog.require('ol.Size');
goog.require('ol.Tile');
@@ -122,7 +123,7 @@ ol.renderer.webgl.Map = function(container, map) {
this.canvas_ = goog.dom.createElement(goog.dom.TagName.CANVAS);
this.canvas_.height = container.clientHeight;
this.canvas_.width = container.clientWidth;
this.canvas_.className = 'ol-unselectable';
this.canvas_.className = ol.CSS_CLASS_UNSELECTABLE;
goog.dom.insertChildAt(container, this.canvas_, 0);
/**
@@ -215,17 +216,6 @@ ol.renderer.webgl.Map = function(container, map) {
goog.inherits(ol.renderer.webgl.Map, ol.renderer.Map);
/**
* @inheritDoc
*/
ol.renderer.webgl.Map.prototype.addLayer = function(layer) {
goog.base(this, 'addLayer', layer);
if (layer.getVisible()) {
this.getMap().render();
}
};
/**
* @param {ol.Tile} tile Tile.
* @param {number} magFilter Mag filter.
@@ -464,17 +454,6 @@ ol.renderer.webgl.Map.prototype.isTileTextureLoaded = function(tile) {
};
/**
* @inheritDoc
*/
ol.renderer.webgl.Map.prototype.removeLayer = function(layer) {
goog.base(this, 'removeLayer', layer);
if (layer.getVisible()) {
this.getMap().render();
}
};
/**
* @inheritDoc
*/
+3 -4
View File
@@ -109,9 +109,8 @@ ol.source.ImageTileSource.prototype.getTile =
/**
* @inheritDoc
*/
ol.source.ImageTileSource.prototype.useTile = function(tileCoord) {
var key = tileCoord.toString();
if (this.tileCache_.containsKey(key)) {
this.tileCache_.get(key);
ol.source.ImageTileSource.prototype.useTile = function(tileCoordKey) {
if (this.tileCache_.containsKey(tileCoordKey)) {
this.tileCache_.get(tileCoordKey);
}
};
+2 -2
View File
@@ -34,11 +34,11 @@ ol.source.SingleImageWMS = function(options) {
this.image_ = null;
/**
* FIXME configurable?
* @private
* @type {number}
*/
this.ratio_ = 1.5;
this.ratio_ = goog.isDef(options.ratio) ?
options.ratio : 1.5;
};
goog.inherits(ol.source.SingleImageWMS, ol.source.ImageSource);
+7 -8
View File
@@ -22,20 +22,19 @@ ol.source.TiledWMS = function(tiledWMSOptions) {
tileGrid = tiledWMSOptions.tileGrid;
}
var tileUrlFunction;
if (tiledWMSOptions.urls) {
var tileUrlFunction = ol.TileUrlFunction.nullTileUrlFunction;
var urls = tiledWMSOptions.urls;
if (!goog.isDef(urls) && goog.isDef(tiledWMSOptions.url)) {
urls = ol.TileUrlFunction.expandUrl(tiledWMSOptions.url);
}
if (goog.isDef(urls)) {
var tileUrlFunctions = goog.array.map(
tiledWMSOptions.urls, function(url) {
urls, function(url) {
return ol.TileUrlFunction.createWMSParams(
url, tiledWMSOptions.params);
});
tileUrlFunction = ol.TileUrlFunction.createFromTileUrlFunctions(
tileUrlFunctions);
} else if (tiledWMSOptions.url) {
tileUrlFunction = ol.TileUrlFunction.createWMSParams(
tiledWMSOptions.url, tiledWMSOptions.params);
} else {
tileUrlFunction = ol.TileUrlFunction.nullTileUrlFunction;
}
var transparent = goog.isDef(tiledWMSOptions.params['TRANSPARENT']) ?
tiledWMSOptions.params['TRANSPARENT'] : true;
+1
View File
@@ -0,0 +1 @@
@exportClass ol.source.Vector ol.source.SourceOptions
+15
View File
@@ -0,0 +1,15 @@
goog.provide('ol.source.Vector');
goog.require('ol.source.Source');
/**
* @constructor
* @extends {ol.source.Source}
* @param {ol.source.SourceOptions} options Source options.
*/
ol.source.Vector = function(options) {
goog.base(this, options);
};
goog.inherits(ol.source.Vector, ol.source.Source);
+17 -31
View File
@@ -2,8 +2,6 @@ goog.provide('ol.source.WMTS');
goog.provide('ol.source.WMTSRequestEncoding');
goog.require('ol.Attribution');
goog.require('ol.Extent');
goog.require('ol.Projection');
goog.require('ol.TileCoord');
goog.require('ol.TileUrlFunction');
goog.require('ol.TileUrlFunctionType');
@@ -66,25 +64,6 @@ ol.source.WMTS = function(wmtsOptions) {
goog.object.extend(kvpParams, context);
}
// TODO: factorize the code below so that it is usable by all sources
var urls = wmtsOptions.urls;
if (!goog.isDef(urls)) {
urls = [];
var url = wmtsOptions.url;
goog.asserts.assert(goog.isDef(url));
var match = /\{(\d)-(\d)\}/.exec(url) || /\{([a-z])-([a-z])\}/.exec(url);
if (match) {
var startCharCode = match[1].charCodeAt(0);
var stopCharCode = match[2].charCodeAt(0);
var charCode;
for (charCode = startCharCode; charCode <= stopCharCode; ++charCode) {
urls.push(url.replace(match[0], String.fromCharCode(charCode)));
}
} else {
urls.push(url);
}
}
/**
* @param {string} template Template.
* @return {ol.TileUrlFunctionType} Tile URL function.
@@ -113,16 +92,23 @@ ol.source.WMTS = function(wmtsOptions) {
};
}
var tileUrlFunction = ol.TileUrlFunction.createFromTileUrlFunctions(
goog.array.map(urls, function(url) {
if (goog.isDef(kvpParams)) {
// TODO: we may want to create our own appendParams function
// so that params order conforms to wmts spec guidance,
// and so that we can avoid to escape special template params
url = goog.uri.utils.appendParamsFromMap(url, kvpParams);
}
return createFromWMTSTemplate(url);
}));
var tileUrlFunction = ol.TileUrlFunction.nullTileUrlFunction;
var urls = wmtsOptions.urls;
if (!goog.isDef(urls) && goog.isDef(wmtsOptions.url)) {
urls = ol.TileUrlFunction.expandUrl(wmtsOptions.url);
}
if (goog.isDef(urls)) {
tileUrlFunction = ol.TileUrlFunction.createFromTileUrlFunctions(
goog.array.map(urls, function(url) {
if (goog.isDef(kvpParams)) {
// TODO: we may want to create our own appendParams function
// so that params order conforms to wmts spec guidance,
// and so that we can avoid to escape special template params
url = goog.uri.utils.appendParamsFromMap(url, kvpParams);
}
return createFromWMTSTemplate(url);
}));
}
tileUrlFunction = ol.TileUrlFunction.withTileCoordTransform(
function(tileCoord, tileGrid, projection) {
+2 -1
View File
@@ -49,7 +49,8 @@ ol.source.XYZ = function(xyzOptions) {
} else if (goog.isDef(xyzOptions.urls)) {
tileUrlFunction = ol.TileUrlFunction.createFromTemplates(xyzOptions.urls);
} else if (goog.isDef(xyzOptions.url)) {
tileUrlFunction = ol.TileUrlFunction.createFromTemplate(xyzOptions.url);
tileUrlFunction = ol.TileUrlFunction.createFromTemplates(
ol.TileUrlFunction.expandUrl(xyzOptions.url));
}
var tileGrid = new ol.tilegrid.XYZ({
+213
View File
@@ -0,0 +1,213 @@
goog.provide('ol.structs.RTree');
goog.require('ol.Rectangle');
/**
* @private
* @constructor
* @param {number} minX Minimum X.
* @param {number} minY Minimum Y.
* @param {number} maxX Maximum X.
* @param {number} maxY Maximum Y.
* @param {ol.structs.RTreeNode_} parent Parent node.
* @param {number} level Level in the tree hierarchy.
* @extends {ol.Rectangle}
*/
ol.structs.RTreeNode_ = function(minX, minY, maxX, maxY, parent, level) {
goog.base(this, minX, minY, maxX, maxY);
/**
* @type {Object}
*/
this.object;
/**
* @type {string}
*/
this.objectId;
/**
* @type {ol.structs.RTreeNode_}
*/
this.parent = parent;
/**
* @type {number}
*/
this.level = level;
/**
* @type {Object.<string, boolean>}
*/
this.types = {};
/**
* @type {Array.<ol.structs.RTreeNode_>}
*/
this.children = [];
};
goog.inherits(ol.structs.RTreeNode_, ol.Rectangle);
/**
* Find all objects intersected by a rectangle.
* @param {ol.Rectangle} bounds Bounding box.
* @param {Object.<string, Object>} results Target object for results.
* @param {string=} opt_type Type for another indexing dimension.
*/
ol.structs.RTreeNode_.prototype.find = function(bounds, results, opt_type) {
if (this.intersects(bounds) &&
(!goog.isDef(opt_type) || this.types[opt_type] === true)) {
var numChildren = this.children.length;
if (numChildren === 0) {
if (goog.isDef(this.object)) {
results[this.objectId] = this.object;
}
} else {
for (var i = 0; i < numChildren; ++i) {
this.children[i].find(bounds, results, opt_type);
}
}
}
};
/**
* Find the appropriate node for insertion.
* @param {ol.Rectangle} bounds Bounding box.
* @return {ol.structs.RTreeNode_|undefined} Matching node.
*/
ol.structs.RTreeNode_.prototype.get = function(bounds) {
if (this.intersects(bounds)) {
var numChildren = this.children.length;
if (numChildren === 0) {
return goog.isNull(this.parent) ? this : this.parent;
}
var node;
for (var i = 0; i < numChildren; ++i) {
node = this.children[i].get(bounds);
if (goog.isDef(node)) {
return node;
}
}
return this;
}
};
/**
* Update boxes up to the root to ensure correct bounding
* @param {ol.Rectangle} bounds Bounding box.
*/
ol.structs.RTreeNode_.prototype.update = function(bounds) {
this.extend(bounds);
if (!goog.isNull(this.parent)) {
this.parent.update(bounds);
}
};
/**
* Divide @this node's children in half and create two new boxes containing
* the split items. The top left will be the topmost leftmost child and the
* bottom right will be the rightmost bottommost child.
*/
ol.structs.RTreeNode_.prototype.divide = function() {
var numChildren = this.children.length;
if (numChildren === 0) {
return;
}
var half = Math.ceil(numChildren / 2),
child, node;
for (var i = 0; i < numChildren; ++i) {
child = this.children[i];
if (i % half === 0) {
node = new ol.structs.RTreeNode_(child.minX, child.minY,
child.maxX, child.maxY, this, this.level + 1);
goog.object.extend(this.types, node.types);
this.children.push(node);
}
child.parent = /** @type {ol.structs.RTreeNode_} */ (node);
goog.object.extend(node.types, child.types);
node.children.push(child);
node.extend(child);
}
};
/**
* @constructor
*/
ol.structs.RTree = function() {
/**
* @private
* @type {ol.structs.RTreeNode_}
*/
this.root_ = new ol.structs.RTreeNode_(
Number.NEGATIVE_INFINITY, Number.NEGATIVE_INFINITY,
Number.POSITIVE_INFINITY, Number.POSITIVE_INFINITY, null, 0);
};
/**
* @param {ol.Rectangle} bounds Bounding box.
* @param {string=} opt_type Type for another indexing dimension.
* @return {Object.<string, Object>} Results for the passed bounding box.
*/
ol.structs.RTree.prototype.find = function(bounds, opt_type) {
var results = /** @type {Object.<string, Object>} */ ({});
this.root_.find(bounds, results, opt_type);
return results;
};
/**
* @param {ol.Rectangle} bounds Bounding box.
* @param {Object} object Object to store with the passed bounds.
* @param {string=} opt_type Type for another indexing dimension.
*/
ol.structs.RTree.prototype.put = function(bounds, object, opt_type) {
var found = this.root_.get(bounds);
if (found) {
var node = new ol.structs.RTreeNode_(
bounds.minX, bounds.minY, bounds.maxX, bounds.maxY,
found, found.level + 1);
node.object = object;
node.objectId = goog.getUid(object).toString();
found.children.push(node);
found.update(bounds);
if (goog.isDef(opt_type)) {
node.types[opt_type] = true;
found.types[opt_type] = true;
}
if (found.children.length >= ol.structs.RTree.MAX_OBJECTS &&
found.level < ol.structs.RTree.MAX_SUB_DIVISIONS) {
found.divide();
}
}
};
/**
* @type {number}
*/
ol.structs.RTree.MAX_SUB_DIVISIONS = 6;
/**
* @type {number}
*/
ol.structs.RTree.MAX_OBJECTS = 6;
+9
View File
@@ -0,0 +1,9 @@
@exportClass ol.style.Icon ol.style.IconOptions
@exportClass ol.style.Line ol.style.LineOptions
@exportClass ol.style.Polygon ol.style.PolygonOptions
@exportClass ol.style.Rule ol.style.RuleOptions
@exportClass ol.style.Shape ol.style.ShapeOptions
@exportClass ol.style.Style ol.style.StyleOptions
@exportSymbol ol.style.IconType
@exportSymbol ol.style.ShapeType
@exportProperty ol.style.ShapeType.CIRCLE
+160
View File
@@ -0,0 +1,160 @@
goog.provide('ol.style.Icon');
goog.provide('ol.style.IconLiteral');
goog.provide('ol.style.IconType');
goog.require('ol.Expression');
goog.require('ol.ExpressionLiteral');
goog.require('ol.style.Point');
goog.require('ol.style.PointLiteral');
/**
* @typedef {{url: (string),
* width: (number|undefined),
* height: (number|undefined),
* opacity: (number),
* rotation: (number)}}
*/
ol.style.IconLiteralOptions;
/**
* @constructor
* @extends {ol.style.PointLiteral}
* @param {ol.style.IconLiteralOptions} config Symbolizer properties.
*/
ol.style.IconLiteral = function(config) {
/** @type {string} */
this.url = config.url;
/** @type {number|undefined} */
this.width = config.width;
/** @type {number|undefined} */
this.height = config.height;
/** @type {number} */
this.opacity = config.opacity;
/** @type {number} */
this.rotation = config.rotation;
};
goog.inherits(ol.style.IconLiteral, ol.style.PointLiteral);
/**
* @inheritDoc
*/
ol.style.IconLiteral.prototype.equals = function(iconLiteral) {
return this.url == iconLiteral.type &&
this.width == iconLiteral.width &&
this.height == iconLiteral.height &&
this.opacity == iconLiteral.opacity &&
this.rotation == iconLiteral.rotation;
};
/**
* @constructor
* @extends {ol.style.Point}
* @param {ol.style.IconOptions} options Symbolizer properties.
*/
ol.style.Icon = function(options) {
goog.asserts.assert(options.url, 'url must be set');
/**
* @type {ol.Expression}
* @private
*/
this.url_ = (options.url instanceof ol.Expression) ?
options.url : new ol.ExpressionLiteral(options.url);
/**
* @type {ol.Expression}
* @private
*/
this.width_ = !goog.isDef(options.width) ?
null :
(options.width instanceof ol.Expression) ?
options.width : new ol.ExpressionLiteral(options.width);
/**
* @type {ol.Expression}
* @private
*/
this.height_ = !goog.isDef(options.height) ?
null :
(options.height instanceof ol.Expression) ?
options.height : new ol.ExpressionLiteral(options.height);
/**
* @type {ol.Expression}
* @private
*/
this.opacity_ = !goog.isDef(options.opacity) ?
new ol.ExpressionLiteral(ol.style.IconDefaults.opacity) :
(options.opacity instanceof ol.Expression) ?
options.opacity : new ol.ExpressionLiteral(options.opacity);
/**
* @type {ol.Expression}
* @private
*/
this.rotation_ = !goog.isDef(options.rotation) ?
new ol.ExpressionLiteral(ol.style.IconDefaults.rotation) :
(options.rotation instanceof ol.Expression) ?
options.rotation : new ol.ExpressionLiteral(options.rotation);
};
/**
* @inheritDoc
* @return {ol.style.IconLiteral} Literal shape symbolizer.
*/
ol.style.Icon.prototype.createLiteral = function(feature) {
var attrs = feature.getAttributes();
var url = /** @type {string} */ (this.url_.evaluate(feature, attrs));
goog.asserts.assert(goog.isString(url) && url != '#', 'url must be a string');
var width = /** @type {number|undefined} */ (goog.isNull(this.width_) ?
undefined : this.width_.evaluate(feature, attrs));
goog.asserts.assert(!goog.isDef(width) || goog.isNumber(width),
'width must be undefined or a number');
var height = /** @type {number|undefined} */ (goog.isNull(this.height_) ?
undefined : this.height_.evaluate(feature, attrs));
goog.asserts.assert(!goog.isDef(height) || goog.isNumber(height),
'height must be undefined or a number');
var opacity = /** {@type {number} */ (this.opacity_.evaluate(feature, attrs));
goog.asserts.assertNumber(opacity, 'opacity must be a number');
var rotation =
/** {@type {number} */ (this.opacity_.evaluate(feature, attrs));
goog.asserts.assertNumber(rotation, 'rotation must be a number');
return new ol.style.IconLiteral({
url: url,
width: width,
height: height,
opacity: opacity,
rotation: rotation
});
};
/**
* @type {ol.style.IconLiteral}
*/
ol.style.IconDefaults = new ol.style.IconLiteral({
url: '#',
opacity: 1,
rotation: 0
});
+128
View File
@@ -0,0 +1,128 @@
goog.provide('ol.style.Line');
goog.provide('ol.style.LineLiteral');
goog.require('ol.Expression');
goog.require('ol.ExpressionLiteral');
goog.require('ol.style.Symbolizer');
goog.require('ol.style.SymbolizerLiteral');
/**
* @typedef {{strokeColor: (string),
* strokeWidth: (number),
* opacity: (number)}}
*/
ol.style.LineLiteralOptions;
/**
* @constructor
* @extends {ol.style.SymbolizerLiteral}
* @param {ol.style.LineLiteralOptions} config Symbolizer properties.
*/
ol.style.LineLiteral = function(config) {
goog.base(this);
goog.asserts.assertString(config.strokeColor, 'strokeColor must be a string');
/** @type {string} */
this.strokeColor = config.strokeColor;
goog.asserts.assertNumber(config.strokeWidth, 'strokeWidth must be a number');
/** @type {number} */
this.strokeWidth = config.strokeWidth;
goog.asserts.assertNumber(config.opacity, 'opacity must be a number');
/** @type {number} */
this.opacity = config.opacity;
};
goog.inherits(ol.style.LineLiteral, ol.style.SymbolizerLiteral);
/**
* @inheritDoc
*/
ol.style.LineLiteral.prototype.equals = function(lineLiteral) {
return this.strokeColor == lineLiteral.strokeColor &&
this.strokeWidth == lineLiteral.strokeWidth &&
this.opacity == lineLiteral.opacity;
};
/**
* @constructor
* @extends {ol.style.Symbolizer}
* @param {ol.style.LineOptions} options Symbolizer properties.
*/
ol.style.Line = function(options) {
goog.base(this);
/**
* @type {ol.Expression}
* @private
*/
this.strokeColor_ = !goog.isDef(options.strokeColor) ?
new ol.ExpressionLiteral(ol.style.LineDefaults.strokeColor) :
(options.strokeColor instanceof ol.Expression) ?
options.strokeColor : new ol.ExpressionLiteral(options.strokeColor);
/**
* @type {ol.Expression}
* @private
*/
this.strokeWidth_ = !goog.isDef(options.strokeWidth) ?
new ol.ExpressionLiteral(ol.style.LineDefaults.strokeWidth) :
(options.strokeWidth instanceof ol.Expression) ?
options.strokeWidth : new ol.ExpressionLiteral(options.strokeWidth);
/**
* @type {ol.Expression}
* @private
*/
this.opacity_ = !goog.isDef(options.opacity) ?
new ol.ExpressionLiteral(ol.style.LineDefaults.opacity) :
(options.opacity instanceof ol.Expression) ?
options.opacity : new ol.ExpressionLiteral(options.opacity);
};
goog.inherits(ol.style.Line, ol.style.Symbolizer);
/**
* @inheritDoc
* @return {ol.style.LineLiteral} Literal line symbolizer.
*/
ol.style.Line.prototype.createLiteral = function(opt_feature) {
var attrs,
feature = opt_feature;
if (goog.isDef(feature)) {
attrs = feature.getAttributes();
}
var strokeColor = this.strokeColor_.evaluate(feature, attrs);
goog.asserts.assertString(strokeColor, 'strokeColor must be a string');
var strokeWidth = this.strokeWidth_.evaluate(feature, attrs);
goog.asserts.assertNumber(strokeWidth, 'strokeWidth must be a number');
var opacity = this.opacity_.evaluate(feature, attrs);
goog.asserts.assertNumber(opacity, 'opacity must be a number');
return new ol.style.LineLiteral({
strokeColor: strokeColor,
strokeWidth: strokeWidth,
opacity: opacity
});
};
/**
* @type {ol.style.LineLiteral}
*/
ol.style.LineDefaults = new ol.style.LineLiteral({
strokeColor: '#696969',
strokeWidth: 1.5,
opacity: 0.75
});
+33
View File
@@ -0,0 +1,33 @@
goog.provide('ol.style.Point');
goog.provide('ol.style.PointLiteral');
goog.require('ol.style.Symbolizer');
goog.require('ol.style.SymbolizerLiteral');
/**
* @constructor
* @extends {ol.style.SymbolizerLiteral}
*/
ol.style.PointLiteral = function() {
goog.base(this);
};
goog.inherits(ol.style.PointLiteral, ol.style.SymbolizerLiteral);
/**
* @constructor
* @extends {ol.style.Symbolizer}
*/
ol.style.Point = function() {
goog.base(this);
};
goog.inherits(ol.style.Point, ol.style.Symbolizer);
/**
* @inheritDoc
*/
ol.style.Point.prototype.createLiteral = goog.abstractMethod;
+189
View File
@@ -0,0 +1,189 @@
goog.provide('ol.style.Polygon');
goog.provide('ol.style.PolygonLiteral');
goog.require('ol.Expression');
goog.require('ol.ExpressionLiteral');
goog.require('ol.style.Symbolizer');
goog.require('ol.style.SymbolizerLiteral');
/**
* @typedef {{fillColor: (string|undefined),
* strokeColor: (string|undefined),
* strokeWidth: (number|undefined),
* opacity: (number)}}
*/
ol.style.PolygonLiteralOptions;
/**
* @constructor
* @extends {ol.style.SymbolizerLiteral}
* @param {ol.style.PolygonLiteralOptions} config Symbolizer properties.
*/
ol.style.PolygonLiteral = function(config) {
goog.base(this);
/** @type {string|undefined} */
this.fillColor = config.fillColor;
if (goog.isDef(config.fillColor)) {
goog.asserts.assertString(config.fillColor, 'fillColor must be a string');
}
/** @type {string|undefined} */
this.strokeColor = config.strokeColor;
if (goog.isDef(this.strokeColor)) {
goog.asserts.assertString(
this.strokeColor, 'strokeColor must be a string');
}
/** @type {number|undefined} */
this.strokeWidth = config.strokeWidth;
if (goog.isDef(this.strokeWidth)) {
goog.asserts.assertNumber(
this.strokeWidth, 'strokeWidth must be a number');
}
goog.asserts.assert(
goog.isDef(this.fillColor) ||
(goog.isDef(this.strokeColor) && goog.isDef(this.strokeWidth)),
'Either fillColor or strokeColor and strokeWidth must be set');
goog.asserts.assertNumber(config.opacity, 'opacity must be a number');
/** @type {number} */
this.opacity = config.opacity;
};
goog.inherits(ol.style.PolygonLiteral, ol.style.SymbolizerLiteral);
/**
* @inheritDoc
*/
ol.style.PolygonLiteral.prototype.equals = function(polygonLiteral) {
return this.fillColor == polygonLiteral.fillColor &&
this.strokeColor == polygonLiteral.strokeColor &&
this.strokeWidth == polygonLiteral.strokeWidth &&
this.opacity == polygonLiteral.opacity;
};
/**
* @constructor
* @extends {ol.style.Symbolizer}
* @param {ol.style.PolygonOptions} options Symbolizer properties.
*/
ol.style.Polygon = function(options) {
goog.base(this);
/**
* @type {ol.Expression}
* @private
*/
this.fillColor_ = !goog.isDefAndNotNull(options.fillColor) ?
null :
(options.fillColor instanceof ol.Expression) ?
options.fillColor : new ol.ExpressionLiteral(options.fillColor);
// stroke handling - if any stroke property is supplied, use defaults
var strokeColor = null,
strokeWidth = null;
if (goog.isDefAndNotNull(options.strokeColor) ||
goog.isDefAndNotNull(options.strokeWidth)) {
strokeColor = !goog.isDefAndNotNull(options.strokeColor) ?
new ol.ExpressionLiteral(ol.style.PolygonDefaults.strokeColor) :
(options.strokeColor instanceof ol.Expression) ?
options.strokeColor : new ol.ExpressionLiteral(options.strokeColor);
strokeWidth = !goog.isDef(options.strokeWidth) ?
new ol.ExpressionLiteral(ol.style.PolygonDefaults.strokeWidth) :
(options.strokeWidth instanceof ol.Expression) ?
options.strokeWidth : new ol.ExpressionLiteral(options.strokeWidth);
}
/**
* @type {ol.Expression}
* @private
*/
this.strokeColor_ = strokeColor;
/**
* @type {ol.Expression}
* @private
*/
this.strokeWidth_ = strokeWidth;
// one of stroke or fill can be null, both null is user error
goog.asserts.assert(!goog.isNull(this.fillColor_) ||
!(goog.isNull(this.strokeColor_) && goog.isNull(this.strokeWidth_)),
'Stroke or fill properties must be provided');
/**
* @type {ol.Expression}
* @private
*/
this.opacity_ = !goog.isDef(options.opacity) ?
new ol.ExpressionLiteral(ol.style.PolygonDefaults.opacity) :
(options.opacity instanceof ol.Expression) ?
options.opacity : new ol.ExpressionLiteral(options.opacity);
};
goog.inherits(ol.style.Polygon, ol.style.Symbolizer);
/**
* @inheritDoc
* @return {ol.style.PolygonLiteral} Literal shape symbolizer.
*/
ol.style.Polygon.prototype.createLiteral = function(opt_feature) {
var attrs,
feature = opt_feature;
if (goog.isDef(feature)) {
attrs = feature.getAttributes();
}
var fillColor = goog.isNull(this.fillColor_) ?
undefined :
/** @type {string} */ (this.fillColor_.evaluate(feature, attrs));
goog.asserts.assert(!goog.isDef(fillColor) || goog.isString(fillColor));
var strokeColor = goog.isNull(this.strokeColor_) ?
undefined :
/** @type {string} */ (this.strokeColor_.evaluate(feature, attrs));
goog.asserts.assert(!goog.isDef(strokeColor) || goog.isString(strokeColor));
var strokeWidth = goog.isNull(this.strokeWidth_) ?
undefined :
/** @type {number} */ (this.strokeWidth_.evaluate(feature, attrs));
goog.asserts.assert(!goog.isDef(strokeWidth) || goog.isNumber(strokeWidth));
goog.asserts.assert(
goog.isDef(fillColor) ||
(goog.isDef(strokeColor) && goog.isDef(strokeWidth)),
'either fill style or strokeColor and strokeWidth must be defined');
var opacity = this.opacity_.evaluate(feature, attrs);
goog.asserts.assertNumber(opacity, 'opacity must be a number');
return new ol.style.PolygonLiteral({
fillColor: fillColor,
strokeColor: strokeColor,
strokeWidth: strokeWidth,
opacity: opacity
});
};
/**
* @type {ol.style.PolygonLiteral}
*/
ol.style.PolygonDefaults = new ol.style.PolygonLiteral({
fillColor: '#ffffff',
strokeColor: '#696969',
strokeWidth: 1.5,
opacity: 0.75
});
+46
View File
@@ -0,0 +1,46 @@
goog.provide('ol.style.Rule');
goog.require('ol.Feature');
goog.require('ol.filter.Filter');
goog.require('ol.style.Symbolizer');
/**
* @constructor
* @param {ol.style.RuleOptions} options Rule options.
*/
ol.style.Rule = function(options) {
/**
* @type {ol.filter.Filter}
* @private
*/
this.filter_ = goog.isDef(options.filter) ? options.filter : null;
/**
* @type {Array.<ol.style.Symbolizer>}
* @private
*/
this.symbolizers_ = goog.isDef(options.symbolizers) ?
options.symbolizers : [];
};
/**
* @param {ol.Feature} feature Feature.
* @return {boolean} Does the rule apply to the feature?
*/
ol.style.Rule.prototype.applies = function(feature) {
return goog.isNull(this.filter_) ? true : this.filter_.applies(feature);
};
/**
* @return {Array.<ol.style.Symbolizer>} Symbolizers.
*/
ol.style.Rule.prototype.getSymbolizers = function() {
return this.symbolizers_;
};
+230
View File
@@ -0,0 +1,230 @@
goog.provide('ol.style.Shape');
goog.provide('ol.style.ShapeLiteral');
goog.provide('ol.style.ShapeType');
goog.require('ol.Expression');
goog.require('ol.ExpressionLiteral');
goog.require('ol.style.Point');
goog.require('ol.style.PointLiteral');
/**
* @enum {string}
*/
ol.style.ShapeType = {
CIRCLE: 'circle'
};
/**
* @typedef {{type: (ol.style.ShapeType),
* size: (number),
* fillColor: (string|undefined),
* strokeColor: (string|undefined),
* strokeWidth: (number|undefined),
* opacity: (number)}}
*/
ol.style.ShapeLiteralOptions;
/**
* @constructor
* @extends {ol.style.PointLiteral}
* @param {ol.style.ShapeLiteralOptions} config Symbolizer properties.
*/
ol.style.ShapeLiteral = function(config) {
goog.asserts.assertString(config.type, 'type must be a string');
/** @type {ol.style.ShapeType} */
this.type = config.type;
goog.asserts.assertNumber(config.size, 'size must be a number');
/** @type {number} */
this.size = config.size;
/** @type {string|undefined} */
this.fillColor = config.fillColor;
if (goog.isDef(config.fillColor)) {
goog.asserts.assertString(config.fillColor, 'fillColor must be a string');
}
/** @type {string|undefined} */
this.strokeColor = config.strokeColor;
if (goog.isDef(this.strokeColor)) {
goog.asserts.assertString(
this.strokeColor, 'strokeColor must be a string');
}
/** @type {number|undefined} */
this.strokeWidth = config.strokeWidth;
if (goog.isDef(this.strokeWidth)) {
goog.asserts.assertNumber(
this.strokeWidth, 'strokeWidth must be a number');
}
goog.asserts.assert(
goog.isDef(this.fillColor) ||
(goog.isDef(this.strokeColor) && goog.isDef(this.strokeWidth)),
'Either fillColor or strokeColor and strokeWidth must be set');
goog.asserts.assertNumber(config.opacity, 'opacity must be a number');
/** @type {number} */
this.opacity = config.opacity;
};
goog.inherits(ol.style.ShapeLiteral, ol.style.PointLiteral);
/**
* @inheritDoc
*/
ol.style.ShapeLiteral.prototype.equals = function(shapeLiteral) {
return this.type == shapeLiteral.type &&
this.size == shapeLiteral.size &&
this.fillColor == shapeLiteral.fillColor &&
this.strokeColor == shapeLiteral.strokeColor &&
this.strokeWidth == shapeLiteral.strokeWidth &&
this.opacity == shapeLiteral.opacity;
};
/**
* @constructor
* @extends {ol.style.Point}
* @param {ol.style.ShapeOptions} options Symbolizer properties.
*/
ol.style.Shape = function(options) {
/**
* @type {ol.style.ShapeType}
* @private
*/
this.type_ = /** @type {ol.style.ShapeType} */ (goog.isDef(options.type) ?
options.type : ol.style.ShapeDefaults.type);
/**
* @type {ol.Expression}
* @private
*/
this.size_ = !goog.isDef(options.size) ?
new ol.ExpressionLiteral(ol.style.ShapeDefaults.size) :
(options.size instanceof ol.Expression) ?
options.size : new ol.ExpressionLiteral(options.size);
/**
* @type {ol.Expression}
* @private
*/
this.fillColor_ = !goog.isDefAndNotNull(options.fillColor) ?
null :
(options.fillColor instanceof ol.Expression) ?
options.fillColor : new ol.ExpressionLiteral(options.fillColor);
// stroke handling - if any stroke property is supplied, use defaults
var strokeColor = null,
strokeWidth = null;
if (goog.isDefAndNotNull(options.strokeColor) ||
goog.isDefAndNotNull(options.strokeWidth)) {
strokeColor = !goog.isDefAndNotNull(options.strokeColor) ?
new ol.ExpressionLiteral(ol.style.ShapeDefaults.strokeColor) :
(options.strokeColor instanceof ol.Expression) ?
options.strokeColor : new ol.ExpressionLiteral(options.strokeColor);
strokeWidth = !goog.isDef(options.strokeWidth) ?
new ol.ExpressionLiteral(ol.style.ShapeDefaults.strokeWidth) :
(options.strokeWidth instanceof ol.Expression) ?
options.strokeWidth : new ol.ExpressionLiteral(options.strokeWidth);
}
/**
* @type {ol.Expression}
* @private
*/
this.strokeColor_ = strokeColor;
/**
* @type {ol.Expression}
* @private
*/
this.strokeWidth_ = strokeWidth;
// one of stroke or fill can be null, both null is user error
goog.asserts.assert(!goog.isNull(this.fillColor_) ||
!(goog.isNull(this.strokeColor_) && goog.isNull(this.strokeWidth_)),
'Stroke or fill properties must be provided');
/**
* @type {ol.Expression}
* @private
*/
this.opacity_ = !goog.isDef(options.opacity) ?
new ol.ExpressionLiteral(ol.style.ShapeDefaults.opacity) :
(options.opacity instanceof ol.Expression) ?
options.opacity : new ol.ExpressionLiteral(options.opacity);
};
/**
* @inheritDoc
* @return {ol.style.ShapeLiteral} Literal shape symbolizer.
*/
ol.style.Shape.prototype.createLiteral = function(opt_feature) {
var attrs,
feature = opt_feature;
if (goog.isDef(feature)) {
attrs = feature.getAttributes();
}
var size = this.size_.evaluate(feature, attrs);
goog.asserts.assertNumber(size, 'size must be a number');
var fillColor = goog.isNull(this.fillColor_) ?
undefined :
/** @type {string} */ (this.fillColor_.evaluate(feature, attrs));
goog.asserts.assert(!goog.isDef(fillColor) || goog.isString(fillColor));
var strokeColor = goog.isNull(this.strokeColor_) ?
undefined :
/** @type {string} */ (this.strokeColor_.evaluate(feature, attrs));
goog.asserts.assert(!goog.isDef(strokeColor) || goog.isString(strokeColor));
var strokeWidth = goog.isNull(this.strokeWidth_) ?
undefined :
/** @type {number} */ (this.strokeWidth_.evaluate(feature, attrs));
goog.asserts.assert(!goog.isDef(strokeWidth) || goog.isNumber(strokeWidth));
goog.asserts.assert(
goog.isDef(fillColor) ||
(goog.isDef(strokeColor) && goog.isDef(strokeWidth)),
'either fill style or strokeColor and strokeWidth must be defined');
var opacity = this.opacity_.evaluate(feature, attrs);
goog.asserts.assertNumber(opacity, 'opacity must be a number');
return new ol.style.ShapeLiteral({
type: this.type_,
size: size,
fillColor: fillColor,
strokeColor: strokeColor,
strokeWidth: strokeWidth,
opacity: opacity
});
};
/**
* @type {ol.style.ShapeLiteral}
*/
ol.style.ShapeDefaults = new ol.style.ShapeLiteral({
type: ol.style.ShapeType.CIRCLE,
size: 5,
fillColor: '#ffffff',
strokeColor: '#696969',
strokeWidth: 1.5,
opacity: 0.75
});
+70
View File
@@ -0,0 +1,70 @@
goog.provide('ol.style.Style');
goog.require('ol.Feature');
goog.require('ol.geom.GeometryType');
goog.require('ol.style.Rule');
goog.require('ol.style.SymbolizerLiteral');
/**
* @constructor
* @param {ol.style.StyleOptions} options Style options.
*/
ol.style.Style = function(options) {
/**
* @type {Array.<ol.style.Rule>}
* @private
*/
this.rules_ = goog.isDef(options.rules) ? options.rules : [];
};
/**
* @param {ol.Feature} feature Feature.
* @return {Array.<ol.style.SymbolizerLiteral>} Symbolizer literals for the
* feature.
*/
ol.style.Style.prototype.apply = function(feature) {
var rules = this.rules_,
literals = [],
rule, symbolizers;
for (var i = 0, ii = rules.length; i < ii; ++i) {
rule = rules[i];
if (rule.applies(feature)) {
symbolizers = rule.getSymbolizers();
for (var j = 0, jj = symbolizers.length; j < jj; ++j) {
literals.push(symbolizers[j].createLiteral(feature));
}
}
}
return literals;
};
/**
* @param {ol.Feature} feature Feature.
* @return {Array.<ol.style.SymbolizerLiteral>} Default symbolizer literals for
* the feature.
*/
ol.style.Style.applyDefaultStyle = function(feature) {
var geometry = feature.getGeometry(),
symbolizerLiterals = [];
if (!goog.isNull(geometry)) {
var type = geometry.getType();
if (type === ol.geom.GeometryType.POINT ||
type === ol.geom.GeometryType.MULTIPOINT) {
symbolizerLiterals.push(ol.style.ShapeDefaults);
} else if (type === ol.geom.GeometryType.LINESTRING ||
type === ol.geom.GeometryType.MULTILINESTRING) {
symbolizerLiterals.push(ol.style.LineDefaults);
} else if (type === ol.geom.GeometryType.LINEARRING ||
type === ol.geom.GeometryType.POLYGON ||
type === ol.geom.GeometryType.MULTIPOLYGON) {
symbolizerLiterals.push(ol.style.PolygonDefaults);
}
}
return symbolizerLiterals;
};
+33
View File
@@ -0,0 +1,33 @@
goog.provide('ol.style.Symbolizer');
goog.provide('ol.style.SymbolizerLiteral');
goog.require('ol.Feature');
/**
* @constructor
*/
ol.style.SymbolizerLiteral = function() {};
/**
* @param {ol.style.SymbolizerLiteral} symbolizerLiteral Symbolizer literal to
* compare to.
* @return {boolean} Is the passed symbolizer literal equal to this instance?
*/
ol.style.SymbolizerLiteral.prototype.equals = goog.abstractMethod;
/**
* @constructor
*/
ol.style.Symbolizer = function() {};
/**
* @param {ol.Feature=} opt_feature Feature for evaluating expressions.
* @return {ol.style.SymbolizerLiteral} Literal symbolizer.
*/
ol.style.Symbolizer.prototype.createLiteral = goog.abstractMethod;
+1 -1
View File
@@ -368,7 +368,7 @@ ol.tilegrid.createForProjection =
resolutions[z] = size / Math.pow(2, z);
}
return new ol.tilegrid.TileGrid({
origin: projectionExtent.getTopLeft(),
origin: projectionExtent.getBottomLeft(),
resolutions: resolutions,
tileSize: tileSize
});
+29 -21
View File
@@ -20,28 +20,15 @@ ol.TileUrlFunctionType;
* @return {ol.TileUrlFunctionType} Tile URL function.
*/
ol.TileUrlFunction.createFromTemplate = function(template) {
var match =
/\{(\d)-(\d)\}/.exec(template) || /\{([a-z])-([a-z])\}/.exec(template);
if (match) {
var templates = [];
var startCharCode = match[1].charCodeAt(0);
var stopCharCode = match[2].charCodeAt(0);
var charCode;
for (charCode = startCharCode; charCode <= stopCharCode; ++charCode) {
templates.push(template.replace(match[0], String.fromCharCode(charCode)));
return function(tileCoord) {
if (goog.isNull(tileCoord)) {
return undefined;
} else {
return template.replace('{z}', tileCoord.z)
.replace('{x}', tileCoord.x)
.replace('{y}', tileCoord.y);
}
return ol.TileUrlFunction.createFromTemplates(templates);
} else {
return function(tileCoord) {
if (goog.isNull(tileCoord)) {
return undefined;
} else {
return template.replace('{z}', tileCoord.z)
.replace('{x}', tileCoord.x)
.replace('{y}', tileCoord.y);
}
};
}
};
};
@@ -120,3 +107,24 @@ ol.TileUrlFunction.withTileCoordTransform =
}
};
};
/**
* @param {string} url Url.
* @return {Array.<string>} Array of urls.
*/
ol.TileUrlFunction.expandUrl = function(url) {
var urls = [];
var match = /\{(\d)-(\d)\}/.exec(url) || /\{([a-z])-([a-z])\}/.exec(url);
if (match) {
var startCharCode = match[1].charCodeAt(0);
var stopCharCode = match[2].charCodeAt(0);
var charCode;
for (charCode = startCharCode; charCode <= stopCharCode; ++charCode) {
urls.push(url.replace(match[0], String.fromCharCode(charCode)));
}
} else {
urls.push(url);
}
return urls;
};