merge with master - solving conflicts

This commit is contained in:
Bart van den Eijnden
2013-08-09 09:55:44 +02:00
209 changed files with 14572 additions and 1847 deletions

View File

@@ -10,9 +10,15 @@ goog.require('goog.asserts');
* @return {number} Index.
*/
ol.array.binaryFindNearest = function(arr, target) {
var index = goog.array.binarySearch(arr, target, function(a, b) {
return b - a;
});
var index = goog.array.binarySearch(arr, target,
/**
* @param {number} a A.
* @param {number} b B.
* @return {number} b minus a.
*/
function(a, b) {
return b - a;
});
if (index >= 0) {
return index;
} else if (index == -1) {

View File

@@ -126,7 +126,7 @@ ol.control.Attribution.prototype.updateElement_ = function(frameState) {
if (goog.isNull(frameState)) {
if (this.renderedVisible_) {
goog.style.showElement(this.element, false);
goog.style.setElementShown(this.element, false);
this.renderedVisible_ = false;
}
return;
@@ -142,14 +142,15 @@ ol.control.Attribution.prototype.updateElement_ = function(frameState) {
for (attributionKey in this.attributionElements_) {
if (attributionKey in visibleAttributions) {
if (!this.attributionElementRenderedVisible_[attributionKey]) {
goog.style.showElement(this.attributionElements_[attributionKey], true);
goog.style.setElementShown(
this.attributionElements_[attributionKey], true);
this.attributionElementRenderedVisible_[attributionKey] = true;
}
delete visibleAttributions[attributionKey];
}
else if (attributionKey in hiddenAttributions) {
if (this.attributionElementRenderedVisible_[attributionKey]) {
goog.style.showElement(
goog.style.setElementShown(
this.attributionElements_[attributionKey], false);
delete this.attributionElementRenderedVisible_[attributionKey];
}
@@ -173,7 +174,7 @@ ol.control.Attribution.prototype.updateElement_ = function(frameState) {
attributionElement = goog.dom.createElement(goog.dom.TagName.LI);
attributionElement.innerHTML =
hiddenAttributions[attributionKey].getHTML();
goog.style.showElement(attributionElement, false);
goog.style.setElementShown(attributionElement, false);
goog.dom.appendChild(this.ulElement_, attributionElement);
this.attributionElements_[attributionKey] = attributionElement;
}
@@ -181,7 +182,7 @@ ol.control.Attribution.prototype.updateElement_ = function(frameState) {
var renderVisible =
!goog.object.isEmpty(this.attributionElementRenderedVisible_);
if (this.renderedVisible_ != renderVisible) {
goog.style.showElement(this.element, renderVisible);
goog.style.setElementShown(this.element, renderVisible);
this.renderedVisible_ = renderVisible;
}

View File

@@ -73,7 +73,7 @@ ol.control.Logo.prototype.updateElement_ = function(frameState) {
if (goog.isNull(frameState)) {
if (this.renderedVisible_) {
goog.style.showElement(this.element, false);
goog.style.setElementShown(this.element, false);
this.renderedVisible_ = false;
}
return;
@@ -104,7 +104,7 @@ ol.control.Logo.prototype.updateElement_ = function(frameState) {
var renderVisible = !goog.object.isEmpty(logos);
if (this.renderedVisible_ != renderVisible) {
goog.style.showElement(this.element, renderVisible);
goog.style.setElementShown(this.element, renderVisible);
this.renderedVisible_ = renderVisible;
}

View File

@@ -194,7 +194,7 @@ ol.control.ScaleLine.prototype.updateElement_ = function() {
if (goog.isNull(view2DState)) {
if (this.renderedVisible_) {
goog.style.showElement(this.element_, false);
goog.style.setElementShown(this.element_, false);
this.renderedVisible_ = false;
}
return;
@@ -322,7 +322,7 @@ ol.control.ScaleLine.prototype.updateElement_ = function() {
}
if (!this.renderedVisible_) {
goog.style.showElement(this.element_, true);
goog.style.setElementShown(this.element_, true);
this.renderedVisible_ = true;
}

View File

@@ -33,6 +33,8 @@ ol.control.Zoom = function(opt_options) {
var className = goog.isDef(options.className) ? options.className : 'ol-zoom';
var delta = goog.isDef(options.delta) ? options.delta : 1;
var inElement = goog.dom.createDom(goog.dom.TagName.A, {
'href': '#zoomIn',
'class': className + '-in'
@@ -40,7 +42,7 @@ ol.control.Zoom = function(opt_options) {
goog.events.listen(inElement, [
goog.events.EventType.TOUCHEND,
goog.events.EventType.CLICK
], this.handleIn_, false, this);
], goog.partial(ol.control.Zoom.prototype.zoomByDelta_, delta), false, this);
var outElement = goog.dom.createDom(goog.dom.TagName.A, {
'href': '#zoomOut',
@@ -49,7 +51,7 @@ ol.control.Zoom = function(opt_options) {
goog.events.listen(outElement, [
goog.events.EventType.TOUCHEND,
goog.events.EventType.CLICK
], this.handleOut_, false, this);
], goog.partial(ol.control.Zoom.prototype.zoomByDelta_, -delta), false, this);
var cssClasses = className + ' ' + ol.css.CLASS_UNSELECTABLE;
var element = goog.dom.createDom(goog.dom.TagName.DIV, cssClasses, inElement,
@@ -61,46 +63,17 @@ ol.control.Zoom = function(opt_options) {
target: options.target
});
/**
* @type {number}
* @private
*/
this.delta_ = goog.isDef(options.delta) ? options.delta : 1;
};
goog.inherits(ol.control.Zoom, ol.control.Control);
/**
* @param {number} delta Zoom delta.
* @param {goog.events.BrowserEvent} browserEvent The browser event to handle.
* @private
*/
ol.control.Zoom.prototype.handleIn_ = function(browserEvent) {
// prevent #zoomIn anchor from getting appended to the url
browserEvent.preventDefault();
var map = this.getMap();
map.requestRenderFrame();
// FIXME works for View2D only
var view = map.getView().getView2D();
var currentResolution = view.getResolution();
if (goog.isDef(currentResolution)) {
map.addPreRenderFunction(ol.animation.zoom({
resolution: currentResolution,
duration: ol.control.ZOOM_DURATION,
easing: ol.easing.easeOut
}));
}
var resolution = view.constrainResolution(currentResolution, this.delta_);
view.setResolution(resolution);
};
/**
* @param {goog.events.BrowserEvent} browserEvent The browser event to handle.
* @private
*/
ol.control.Zoom.prototype.handleOut_ = function(browserEvent) {
// prevent #zoomOut anchor from getting appended to the url
ol.control.Zoom.prototype.zoomByDelta_ = function(delta, browserEvent) {
// prevent the anchor from getting appended to the url
browserEvent.preventDefault();
var map = this.getMap();
// FIXME works for View2D only
@@ -112,7 +85,7 @@ ol.control.Zoom.prototype.handleOut_ = function(browserEvent) {
duration: ol.control.ZOOM_DURATION,
easing: ol.easing.easeOut
}));
var newResolution = view.constrainResolution(currentResolution, delta);
view.setResolution(newResolution);
}
var resolution = view.constrainResolution(currentResolution, -this.delta_);
view.setResolution(resolution);
};

View File

@@ -62,6 +62,13 @@ ol.control.ZoomSlider = function(opt_options) {
*/
this.direction_ = ol.control.ZoomSlider.direction.VERTICAL;
/**
* Whether the slider is initialized.
* @type {boolean}
* @private
*/
this.sliderInitialized_ = false;
/**
* @private
* @type {Array.<?number>}
@@ -107,11 +114,8 @@ ol.control.ZoomSlider.direction = {
*/
ol.control.ZoomSlider.prototype.setMap = function(map) {
goog.base(this, 'setMap', map);
this.initSlider_();
var resolution = map.getView().getView2D().getResolution();
if (goog.isDef(resolution)) {
this.currentResolution_ = resolution;
this.positionThumbForResolution_(resolution);
if (!goog.isNull(map)) {
map.render();
}
};
@@ -147,6 +151,7 @@ ol.control.ZoomSlider.prototype.initSlider_ = function() {
limits = new goog.math.Rect(0, 0, 0, h);
}
this.dragger_.setLimits(limits);
this.sliderInitialized_ = true;
};
@@ -154,6 +159,14 @@ ol.control.ZoomSlider.prototype.initSlider_ = function() {
* @inheritDoc
*/
ol.control.ZoomSlider.prototype.handleMapPostrender = function(mapEvent) {
if (goog.isNull(mapEvent.frameState)) {
return;
}
goog.asserts.assert(
goog.isDefAndNotNull(mapEvent.frameState.view2DState));
if (!this.sliderInitialized_) {
this.initSlider_();
}
var res = mapEvent.frameState.view2DState.resolution;
if (res !== this.currentResolution_) {
this.currentResolution_ = res;

View File

@@ -0,0 +1 @@
@exportClass ol.control.ZoomToExtent ol.control.ZoomToExtentOptions

View File

@@ -0,0 +1,68 @@
// FIXME works for View2D only
goog.provide('ol.control.ZoomToExtent');
goog.require('goog.dom');
goog.require('goog.dom.TagName');
goog.require('goog.events');
goog.require('goog.events.EventType');
goog.require('ol.control.Control');
goog.require('ol.css');
/**
* Create a control that adds a button, which, when pressed, changes
* the map view to a specific extent. To style this control use the
* css selector .ol-zoom-extent.
* @constructor
* @extends {ol.control.Control}
* @param {ol.control.ZoomToExtentOptions=} opt_options Options.
*/
ol.control.ZoomToExtent = function(opt_options) {
var options = goog.isDef(opt_options) ? opt_options : {};
/**
* @type {ol.Extent}
* @private
*/
this.extent_ = goog.isDef(options.extent) ? options.extent : null;
var className = goog.isDef(options.className) ? options.className :
'ol-zoom-extent';
var element = goog.dom.createDom(goog.dom.TagName.DIV, {
'class': className + ' ' + ol.css.CLASS_UNSELECTABLE
});
var button = goog.dom.createDom(goog.dom.TagName.A, {
'href': '#zoomExtent'
});
goog.dom.appendChild(element, button);
goog.events.listen(element, [
goog.events.EventType.TOUCHEND,
goog.events.EventType.CLICK
], this.handleZoomToExtent_, false, this);
goog.base(this, {
element: element,
map: options.map,
target: options.target
});
};
goog.inherits(ol.control.ZoomToExtent, ol.control.Control);
/**
* @param {goog.events.BrowserEvent} browserEvent Browser event.
* @private
*/
ol.control.ZoomToExtent.prototype.handleZoomToExtent_ = function(browserEvent) {
// prevent #zoomExtent anchor from getting appended to the url
browserEvent.preventDefault();
var map = this.getMap();
var view = map.getView().getView2D();
var extent = goog.isNull(this.extent_) ?
view.getProjection().getExtent() : this.extent_;
view.fitExtent(extent, map.getSize());
};

View File

@@ -33,7 +33,7 @@ ol.DeviceOrientation = function(opt_options) {
/**
* @private
* @type {?number}
* @type {goog.events.Key}
*/
this.listenerKey_ = null;

View File

@@ -215,7 +215,9 @@ ol.extent.getForView2DAndSize =
var dy = resolution * size[1] / 2;
var cosRotation = Math.cos(rotation);
var sinRotation = Math.sin(rotation);
/** @type {Array.<number>} */
var xs = [-dx, -dx, dx, dx];
/** @type {Array.<number>} */
var ys = [-dy, dy, -dy, dy];
var i, x, y;
for (i = 0; i < 4; ++i) {

View File

@@ -27,6 +27,42 @@ ol.geom.LinearRing = function(coordinates, opt_shared) {
goog.inherits(ol.geom.LinearRing, ol.geom.LineString);
/**
* Determine if a vertex array representing a linear ring is in clockwise
* order.
*
* This method comes from Green's Theorem and was mentioned in an answer to a
* a Stack Overflow question (http://tinyurl.com/clockwise-method).
*
* Note that calculating the cross product for each pair of edges could be
* avoided by first finding the lowest, rightmost vertex. See OGR's
* implementation for an example of this.
* https://github.com/OSGeo/gdal/blob/trunk/gdal/ogr/ogrlinearring.cpp
*
* @param {ol.geom.VertexArray} coordinates Linear ring coordinates.
* @return {boolean} The coordinates are in clockwise order.
*/
ol.geom.LinearRing.isClockwise = function(coordinates) {
var length = coordinates.length;
var edge = 0;
var last = coordinates[length - 1];
var x1 = last[0];
var y1 = last[1];
var x2, y2, coord;
for (var i = 0; i < length; ++i) {
coord = coordinates[i];
x2 = coord[0];
y2 = coord[1];
edge += (x2 - x1) * (y2 + y1);
x1 = x2;
y1 = y2;
}
return edge > 0;
};
/**
* @inheritDoc
*/

View File

@@ -1,6 +1,7 @@
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');
@@ -10,6 +11,12 @@ goog.require('ol.geom.VertexArray');
/**
* Create a polygon from an array of vertex arrays. Coordinates for the
* exterior ring will be forced to clockwise order. Coordinates for any
* interior rings will be forced to counter-clockwise order. In cases where
* the opposite winding order occurs in the passed vertex arrays, they will
* be modified in place.
*
* @constructor
* @extends {ol.geom.Geometry}
* @param {Array.<ol.geom.VertexArray>} coordinates Array of rings. First
@@ -29,6 +36,12 @@ ol.geom.Polygon = function(coordinates, opt_shared) {
vertices = new ol.geom.SharedVertices({dimension: dimension});
}
/**
* @private
* @type {ol.Coordinate}
*/
this.labelPoint_ = null;
/**
* @type {ol.geom.SharedVertices}
*/
@@ -40,8 +53,21 @@ ol.geom.Polygon = function(coordinates, opt_shared) {
* @type {Array.<ol.geom.LinearRing>}
*/
this.rings = new Array(numRings);
var ringCoords;
for (var i = 0; i < numRings; ++i) {
this.rings[i] = new ol.geom.LinearRing(coordinates[i], vertices);
ringCoords = coordinates[i];
if (i === 0) {
// force exterior ring to be clockwise
if (!ol.geom.LinearRing.isClockwise(ringCoords)) {
ringCoords.reverse();
}
} else {
// force interior rings to be counter-clockwise
if (ol.geom.LinearRing.isClockwise(ringCoords)) {
ringCoords.reverse();
}
}
this.rings[i] = new ol.geom.LinearRing(ringCoords, vertices);
}
/**
@@ -107,3 +133,49 @@ ol.geom.Polygon.prototype.containsCoordinate = function(coordinate) {
}
return containsCoordinate;
};
/**
* Calculates a point that is guaranteed to lie in the interior of the polygon.
* Inspired by JTS's com.vividsolutions.jts.geom.Geometry#getInteriorPoint.
* @return {ol.Coordinate} A point which is in the interior of the polygon.
*/
ol.geom.Polygon.prototype.getInteriorPoint = function() {
if (goog.isNull(this.labelPoint_)) {
var center = ol.extent.getCenter(this.getBounds()),
resultY = center[1],
vertices = this.rings[0].getCoordinates(),
intersections = [],
maxLength = 0,
i, vertex1, vertex2, x, segmentLength, resultX;
// Calculate intersections with the horizontal bounding box center line
for (i = vertices.length - 1; i >= 1; --i) {
vertex1 = vertices[i];
vertex2 = vertices[i - 1];
if ((vertex1[1] >= resultY && vertex2[1] <= resultY) ||
(vertex1[1] <= resultY && vertex2[1] >= resultY)) {
x = (resultY - vertex1[1]) / (vertex2[1] - vertex1[1]) *
(vertex2[0] - vertex1[0]) + vertex1[0];
intersections.push(x);
}
}
// Find the longest segment of the horizontal bounding box center line that
// has its center point inside the polygon
intersections.sort();
for (i = intersections.length - 1; i >= 1; --i) {
segmentLength = Math.abs(intersections[i] - intersections[i - 1]);
if (segmentLength > maxLength) {
x = (intersections[i] + intersections[i - 1]) / 2;
if (this.containsCoordinate([x, resultY])) {
maxLength = segmentLength;
resultX = x;
}
}
}
this.labelPoint_ = [resultX, resultY];
}
return this.labelPoint_;
};

View File

@@ -87,7 +87,7 @@ ol.geom2.LineStringCollection.pack =
goog.asserts.assert(unpackedLineStrings[i].length > 1);
start = offset;
offset = ol.geom2.packPoints(arr, offset, unpackedLineStrings[i], dim);
ranges[/** @type {string} */ (start)] = offset;
ranges[start + ''] = offset;
}
goog.asserts.assert(offset <= capacity);
var buf = new ol.structs.Buffer(arr, offset);
@@ -103,7 +103,7 @@ ol.geom2.LineStringCollection.prototype.add = function(lineString) {
var n = lineString.length * this.dim;
var offset = this.buf.allocate(n);
goog.asserts.assert(offset != -1);
this.ranges[/** @type {string} */ (offset)] = offset + n;
this.ranges[offset + ''] = offset + n;
ol.geom2.packPoints(this.buf.getArray(), offset, lineString, this.dim);
return offset;
};
@@ -115,7 +115,7 @@ ol.geom2.LineStringCollection.prototype.add = function(lineString) {
*/
ol.geom2.LineStringCollection.prototype.get = function(offset) {
goog.asserts.assert(offset in this.ranges);
var range = this.ranges[/** @type {string} */ (offset)];
var range = this.ranges[offset + ''];
return ol.geom2.unpackPoints(
this.buf.getArray(), offset, range, this.dim);
};
@@ -165,9 +165,9 @@ ol.geom2.LineStringCollection.prototype.getIndices = function() {
*/
ol.geom2.LineStringCollection.prototype.remove = function(offset) {
goog.asserts.assert(offset in this.ranges);
var range = this.ranges[/** @type {string} */ (offset)];
var range = this.ranges[offset + ''];
this.buf.remove(range - offset, offset);
delete this.ranges[/** @type {string} */ (offset)];
delete this.ranges[offset + ''];
};
@@ -179,7 +179,7 @@ ol.geom2.LineStringCollection.prototype.remove = function(offset) {
ol.geom2.LineStringCollection.prototype.set = function(offset, lineString) {
var dim = this.dim;
goog.asserts.assert(offset in this.ranges);
var range = this.ranges[/** @type {string} */ (offset)];
var range = this.ranges[offset + ''];
if (lineString.length * dim == range - offset) {
ol.geom2.packPoints(this.buf.getArray(), offset, lineString, dim);
this.buf.markDirty(range - offset, offset);

View File

@@ -34,6 +34,8 @@ ol.ImageState = {
*/
ol.Image = function(extent, resolution, src, crossOrigin, attributions) {
goog.base(this);
/**
* @private
* @type {Array.<ol.Attribution>}

View File

@@ -41,6 +41,7 @@ goog.inherits(ol.interaction.DoubleClickZoom, ol.interaction.Interaction);
*/
ol.interaction.DoubleClickZoom.prototype.handleMapBrowserEvent =
function(mapBrowserEvent) {
var stopEvent = false;
var browserEvent = mapBrowserEvent.browserEvent;
if (mapBrowserEvent.type == ol.MapBrowserEvent.EventType.DBLCLICK &&
mapBrowserEvent.isMouseActionButton()) {
@@ -52,6 +53,7 @@ ol.interaction.DoubleClickZoom.prototype.handleMapBrowserEvent =
ol.interaction.Interaction.zoomByDelta(map, view, delta, anchor,
ol.interaction.DOUBLECLICKZOOM_ANIMATION_DURATION);
mapBrowserEvent.preventDefault();
mapBrowserEvent.stopOtherInteractions();
stopEvent = true;
}
return !stopEvent;
};

View File

@@ -95,8 +95,9 @@ ol.interaction.Drag.prototype.handleMapBrowserEvent =
function(mapBrowserEvent) {
var map = mapBrowserEvent.map;
if (!map.isDef()) {
return;
return true;
}
var stopEvent = false;
var view = map.getView();
var browserEvent = mapBrowserEvent.browserEvent;
if (mapBrowserEvent.type == ol.MapBrowserEvent.EventType.DOWN) {
@@ -119,11 +120,12 @@ ol.interaction.Drag.prototype.handleMapBrowserEvent =
}
} else if (mapBrowserEvent.type == ol.MapBrowserEvent.EventType.DRAGSTART) {
goog.asserts.assertInstanceof(browserEvent, goog.events.BrowserEvent);
var view2DState = view.getView2D().getView2DState();
this.startX = browserEvent.clientX;
this.startY = browserEvent.clientY;
this.deltaX = 0;
this.deltaY = 0;
this.startCenter = /** @type {!ol.Coordinate} */ (view.getCenter());
this.startCenter = view2DState.center;
this.startCoordinate = /** @type {ol.Coordinate} */
(mapBrowserEvent.getCoordinate());
var handled = this.handleDragStart(mapBrowserEvent);
@@ -131,7 +133,8 @@ ol.interaction.Drag.prototype.handleMapBrowserEvent =
view.setHint(ol.ViewHint.INTERACTING, 1);
this.dragging_ = true;
mapBrowserEvent.preventDefault();
mapBrowserEvent.stopOtherInteractions();
stopEvent = true;
}
}
return !stopEvent;
};

View File

@@ -80,16 +80,16 @@ ol.interaction.DragPan.prototype.handleDragEnd = function(mapBrowserEvent) {
// FIXME works for View2D only
var map = mapBrowserEvent.map;
var view = map.getView();
var view = map.getView().getView2D();
if (this.kinetic_ && this.kinetic_.end()) {
var view2DState = view.getView2DState();
var distance = this.kinetic_.getDistance();
var angle = this.kinetic_.getAngle();
var center = view.getCenter();
this.kineticPreRenderFn_ = this.kinetic_.pan(center);
this.kineticPreRenderFn_ = this.kinetic_.pan(view2DState.center);
map.addPreRenderFunction(this.kineticPreRenderFn_);
var centerpx = map.getPixelFromCoordinate(center);
var centerpx = map.getPixelFromCoordinate(view2DState.center);
var dest = map.getCoordinateFromPixel([
centerpx[0] - distance * Math.cos(angle),
centerpx[1] - distance * Math.sin(angle)

View File

@@ -72,15 +72,16 @@ ol.interaction.DragRotateAndZoom.prototype.handleDrag =
var magnitude = delta.magnitude();
// FIXME works for View2D only
var view = map.getView().getView2D();
var view2DState = view.getView2DState();
map.requestRenderFrame();
if (goog.isDef(this.lastAngle_)) {
var angleDelta = theta - this.lastAngle_;
ol.interaction.Interaction.rotateWithoutConstraints(
map, view, view.getRotation() - angleDelta);
map, view, view2DState.rotation - angleDelta);
}
this.lastAngle_ = theta;
if (goog.isDef(this.lastMagnitude_)) {
var resolution = this.lastMagnitude_ * (view.getResolution() / magnitude);
var resolution = this.lastMagnitude_ * (view2DState.resolution / magnitude);
ol.interaction.Interaction.zoomWithoutConstraints(map, view, resolution);
}
if (goog.isDef(this.lastMagnitude_)) {
@@ -96,12 +97,15 @@ ol.interaction.DragRotateAndZoom.prototype.handleDrag =
ol.interaction.DragRotateAndZoom.prototype.handleDragEnd =
function(mapBrowserEvent) {
var map = mapBrowserEvent.map;
// FIXME works for View2D only
var view = map.getView().getView2D();
var view2DState = view.getView2DState();
var direction = this.lastScaleDelta_ - 1;
map.withFrozenRendering(function() {
ol.interaction.Interaction.rotate(map, view, view.getRotation());
ol.interaction.Interaction.zoom(map, view, view.getResolution(), undefined,
ol.interaction.DRAGROTATEANDZOOM_ANIMATION_DURATION, direction);
ol.interaction.Interaction.rotate(map, view, view2DState.rotation);
ol.interaction.Interaction.zoom(map, view, view2DState.resolution,
undefined, ol.interaction.DRAGROTATEANDZOOM_ANIMATION_DURATION,
direction);
});
this.lastScaleDelta_ = 0;
return true;

View File

@@ -1,7 +1,6 @@
goog.provide('ol.interaction.DragRotate');
goog.require('goog.asserts');
goog.require('ol.View2D');
goog.require('ol.interaction.ConditionType');
goog.require('ol.interaction.Drag');
goog.require('ol.interaction.Interaction');
@@ -54,12 +53,12 @@ ol.interaction.DragRotate.prototype.handleDrag = function(mapBrowserEvent) {
Math.atan2(size[1] / 2 - offset[1], offset[0] - size[0] / 2);
if (goog.isDef(this.lastAngle_)) {
var delta = theta - this.lastAngle_;
var view = map.getView();
// FIXME supports View2D only
goog.asserts.assertInstanceof(view, ol.View2D);
// FIXME works for View2D only
var view = map.getView().getView2D();
var view2DState = view.getView2DState();
map.requestRenderFrame();
ol.interaction.Interaction.rotateWithoutConstraints(
map, view, view.getRotation() - delta);
map, view, view2DState.rotation - delta);
}
this.lastAngle_ = theta;
};
@@ -70,10 +69,10 @@ ol.interaction.DragRotate.prototype.handleDrag = function(mapBrowserEvent) {
*/
ol.interaction.DragRotate.prototype.handleDragEnd = function(mapBrowserEvent) {
var map = mapBrowserEvent.map;
// FIXME supports View2D only
var view = map.getView();
goog.asserts.assertInstanceof(view, ol.View2D);
ol.interaction.Interaction.rotate(map, view, view.getRotation(), undefined,
// FIXME works for View2D only
var view = map.getView().getView2D();
var view2DState = view.getView2DState();
ol.interaction.Interaction.rotate(map, view, view2DState.rotation, undefined,
ol.interaction.DRAGROTATE_ANIMATION_DURATION);
};
@@ -86,9 +85,6 @@ ol.interaction.DragRotate.prototype.handleDragStart =
var browserEvent = mapBrowserEvent.browserEvent;
if (browserEvent.isMouseActionButton() && this.condition_(browserEvent)) {
var map = mapBrowserEvent.map;
// FIXME supports View2D only
var view = map.getView();
goog.asserts.assertInstanceof(view, ol.View2D);
map.requestRenderFrame();
this.lastAngle_ = undefined;
return true;

View File

@@ -17,6 +17,9 @@ ol.interaction.Interaction = function() {
/**
* @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event.
* @return {boolean} Whether the map browser event should continue
* through the chain of interactions. false means stop, true
* means continue.
*/
ol.interaction.Interaction.prototype.handleMapBrowserEvent =
goog.abstractMethod;

View File

@@ -52,6 +52,7 @@ goog.inherits(ol.interaction.KeyboardPan, ol.interaction.Interaction);
*/
ol.interaction.KeyboardPan.prototype.handleMapBrowserEvent =
function(mapBrowserEvent) {
var stopEvent = false;
if (mapBrowserEvent.type == goog.events.KeyHandler.EventType.KEY) {
var keyEvent = /** @type {goog.events.KeyEvent} */
(mapBrowserEvent.browserEvent);
@@ -81,7 +82,8 @@ ol.interaction.KeyboardPan.prototype.handleMapBrowserEvent =
ol.interaction.Interaction.pan(
map, view, delta, ol.interaction.KEYBOARD_PAN_DURATION);
mapBrowserEvent.preventDefault();
mapBrowserEvent.stopOtherInteractions();
stopEvent = true;
}
}
return !stopEvent;
};

View File

@@ -49,6 +49,7 @@ goog.inherits(ol.interaction.KeyboardZoom, ol.interaction.Interaction);
*/
ol.interaction.KeyboardZoom.prototype.handleMapBrowserEvent =
function(mapBrowserEvent) {
var stopEvent = false;
if (mapBrowserEvent.type == goog.events.KeyHandler.EventType.KEY) {
var keyEvent = /** @type {goog.events.KeyEvent} */
(mapBrowserEvent.browserEvent);
@@ -63,7 +64,8 @@ ol.interaction.KeyboardZoom.prototype.handleMapBrowserEvent =
ol.interaction.Interaction.zoomByDelta(map, view, delta, undefined,
ol.interaction.KEYBOARD_ZOOM_DURATION);
mapBrowserEvent.preventDefault();
mapBrowserEvent.stopOtherInteractions();
stopEvent = true;
}
}
return !stopEvent;
};

View File

@@ -70,7 +70,7 @@ goog.inherits(ol.interaction.MouseWheelZoom, ol.interaction.Interaction);
*/
ol.interaction.MouseWheelZoom.prototype.handleMapBrowserEvent =
function(mapBrowserEvent) {
var stopEvent = false;
if (mapBrowserEvent.type ==
goog.events.MouseWheelHandler.EventType.MOUSEWHEEL) {
var map = mapBrowserEvent.map;
@@ -93,8 +93,9 @@ ol.interaction.MouseWheelZoom.prototype.handleMapBrowserEvent =
goog.bind(this.doZoom_, this, map), timeLeft);
mapBrowserEvent.preventDefault();
mapBrowserEvent.stopOtherInteractions();
stopEvent = true;
}
return !stopEvent;
};

View File

@@ -126,4 +126,5 @@ ol.interaction.Touch.prototype.handleMapBrowserEvent =
}
this.handled_ = handled;
}
return true;
};

View File

@@ -61,11 +61,12 @@ ol.interaction.TouchPan.prototype.handleTouchMove = function(mapBrowserEvent) {
var deltaX = this.lastCentroid[0] - centroid[0];
var deltaY = centroid[1] - this.lastCentroid[1];
var map = mapBrowserEvent.map;
var view = map.getView();
var view = map.getView().getView2D();
var view2DState = view.getView2DState();
var center = [deltaX, deltaY];
ol.coordinate.scale(center, view.getResolution());
ol.coordinate.rotate(center, view.getRotation());
ol.coordinate.add(center, view.getCenter());
ol.coordinate.scale(center, view2DState.resolution);
ol.coordinate.rotate(center, view2DState.rotation);
ol.coordinate.add(center, view2DState.center);
map.requestRenderFrame();
view.setCenter(center);
}

View File

@@ -101,10 +101,12 @@ ol.interaction.TouchRotate.prototype.handleTouchMove =
// rotate
if (this.rotating_) {
// FIXME works for View2D only
var view = map.getView().getView2D();
var view2DState = view.getView2DState();
map.requestRenderFrame();
ol.interaction.Interaction.rotateWithoutConstraints(map, view,
view.getRotation() + rotationDelta, this.anchor_);
view2DState.rotation + rotationDelta, this.anchor_);
}
};
@@ -116,10 +118,12 @@ ol.interaction.TouchRotate.prototype.handleTouchEnd =
function(mapBrowserEvent) {
if (this.targetTouches.length < 2) {
var map = mapBrowserEvent.map;
// FIXME works for View2D only
var view = map.getView().getView2D();
var view2DState = view.getView2DState();
if (this.rotating_) {
ol.interaction.Interaction.rotate(
map, view, view.getRotation(), this.anchor_,
map, view, view2DState.rotation, this.anchor_,
ol.interaction.TOUCHROTATE_ANIMATION_DURATION);
}
return false;

View File

@@ -71,7 +71,9 @@ ol.interaction.TouchZoom.prototype.handleTouchMove =
}
var map = mapBrowserEvent.map;
// FIXME works for View2D only
var view = map.getView().getView2D();
var view2DState = view.getView2DState();
// scale anchor point.
var viewportPosition = goog.style.getClientPosition(map.getViewport());
@@ -83,7 +85,7 @@ ol.interaction.TouchZoom.prototype.handleTouchMove =
// scale, bypass the resolution constraint
map.requestRenderFrame();
ol.interaction.Interaction.zoomWithoutConstraints(
map, view, view.getResolution() * scaleDelta, this.anchor_);
map, view, view2DState.resolution * scaleDelta, this.anchor_);
};
@@ -95,12 +97,14 @@ ol.interaction.TouchZoom.prototype.handleTouchEnd =
function(mapBrowserEvent) {
if (this.targetTouches.length < 2) {
var map = mapBrowserEvent.map;
// FIXME works for View2D only
var view = map.getView().getView2D();
var view2DState = view.getView2DState();
// Zoom to final resolution, with an animation, and provide a
// direction not to zoom out/in if user was pinching in/out.
// Direction is > 0 if pinching out, and < 0 if pinching in.
var direction = this.lastScaleDelta_ - 1;
ol.interaction.Interaction.zoom(map, view, view.getResolution(),
ol.interaction.Interaction.zoom(map, view, view2DState.resolution,
this.anchor_, ol.interaction.TOUCHZOOM_ANIMATION_DURATION, direction);
return false;
} else {

View File

@@ -108,10 +108,15 @@ ol.Kinetic.prototype.pan = function(source) {
var initialVelocity = this.initialVelocity_;
var minVelocity = this.minVelocity_;
var duration = this.getDuration_();
var easingFunction = function(t) {
return initialVelocity * (Math.exp((decay * t) * duration) - 1) /
(minVelocity - initialVelocity);
};
var easingFunction = (
/**
* @param {number} t T.
* @return {number} Easing.
*/
function(t) {
return initialVelocity * (Math.exp((decay * t) * duration) - 1) /
(minVelocity - initialVelocity);
});
return ol.animation.pan({
source: source,
duration: duration,

View File

@@ -0,0 +1,2 @@
@exportSymbol ol.layer.Layer
@exportProperty ol.layer.Layer.prototype.getSource

View File

@@ -5,6 +5,7 @@ goog.provide('ol.layer.LayerState');
goog.require('goog.events');
goog.require('goog.events.EventType');
goog.require('goog.math');
goog.require('goog.object');
goog.require('ol.Object');
goog.require('ol.source.Source');
@@ -50,12 +51,23 @@ ol.layer.Layer = function(options) {
*/
this.source_ = options.source;
this.setBrightness(goog.isDef(options.brightness) ? options.brightness : 0);
this.setContrast(goog.isDef(options.contrast) ? options.contrast : 1);
this.setHue(goog.isDef(options.hue) ? options.hue : 0);
this.setOpacity(goog.isDef(options.opacity) ? options.opacity : 1);
this.setSaturation(goog.isDef(options.saturation) ? options.saturation : 1);
this.setVisible(goog.isDef(options.visible) ? options.visible : true);
var values = goog.object.clone(options);
delete values.source;
/** @type {number} */
values.brightness = goog.isDef(values.brightness) ? values.brightness : 0;
/** @type {number} */
values.contrast = goog.isDef(values.contrast) ? values.contrast : 1;
/** @type {number} */
values.hue = goog.isDef(values.hue) ? values.hue : 0;
/** @type {number} */
values.opacity = goog.isDef(values.opacity) ? values.opacity : 1;
/** @type {number} */
values.saturation = goog.isDef(values.saturation) ? values.saturation : 1;
/** @type {boolean} */
values.visible = goog.isDef(values.visible) ? values.visible : true;
this.setValues(values);
if (!this.source_.isReady()) {
goog.events.listenOnce(this.source_, goog.events.EventType.LOAD,

View File

@@ -1,4 +1 @@
@exportClass ol.layer.Vector ol.layer.VectorLayerOptions
@exportProperty ol.layer.Vector.prototype.addFeatures
@exportProperty ol.layer.Vector.prototype.parseFeatures

View File

@@ -10,6 +10,7 @@ goog.require('ol.expr.Literal');
goog.require('ol.expr.Logical');
goog.require('ol.expr.LogicalOp');
goog.require('ol.expr.functions');
goog.require('ol.extent');
goog.require('ol.geom.GeometryType');
goog.require('ol.geom.SharedVertices');
goog.require('ol.layer.Layer');
@@ -200,6 +201,34 @@ ol.layer.FeatureCache.prototype.getFeaturesByIds_ = function(ids) {
};
/**
* Remove a feature from the cache.
* @param {ol.Feature} feature Feature.
*/
ol.layer.FeatureCache.prototype.remove = function(feature) {
var id = goog.getUid(feature).toString(),
geometry = feature.getGeometry();
delete this.idLookup_[id];
// index by geometry type and bounding box
if (!goog.isNull(geometry)) {
var geometryType = geometry.getType();
delete this.geometryTypeIndex_[geometryType][id];
this.rTree_.remove(geometry.getBounds(), feature);
}
};
/**
* TODO: Create a VectorLayerEvent with ADD and REMOVE event types
* @typedef {{extent: (ol.Extent|undefined),
* features: (Array.<ol.Feature>|undefined),
* type: goog.events.EventType}}
*/
ol.layer.VectorLayerEventObject;
/**
* @constructor
@@ -262,11 +291,21 @@ goog.inherits(ol.layer.Vector, ol.layer.Layer);
* @param {Array.<ol.Feature>} features Array of features.
*/
ol.layer.Vector.prototype.addFeatures = function(features) {
var extent = ol.extent.createEmpty(),
feature, geometry;
for (var i = 0, ii = features.length; i < ii; ++i) {
this.featureCache_.add(features[i]);
feature = features[i];
this.featureCache_.add(feature);
geometry = feature.getGeometry();
if (!goog.isNull(geometry)) {
ol.extent.extend(extent, geometry.getBounds());
}
}
// TODO: events for real - listeners want features and extent here
this.dispatchEvent(goog.events.EventType.CHANGE);
this.dispatchEvent(/** @type {ol.layer.VectorLayerEventObject} */ ({
extent: extent,
features: features,
type: goog.events.EventType.CHANGE
}));
};
@@ -279,34 +318,26 @@ ol.layer.Vector.prototype.getVectorSource = function() {
/**
* @param {ol.expr.Expression=} opt_expr Expression for filtering.
* @return {Array.<ol.Feature>} Array of features.
*/
ol.layer.Vector.prototype.getFeatures = function(opt_expr) {
return goog.object.getValues(
this.featureCache_.getFeaturesObject(opt_expr));
};
/**
* @param {ol.expr.Expression=} opt_expr Expression for filtering.
* @return {Object.<string, ol.Feature>} Features.
*/
ol.layer.Vector.prototype.getFeaturesObject = function(opt_expr) {
return this.featureCache_.getFeaturesObject(opt_expr);
};
/**
* Get all features whose bounding box intersects the provided extent.
* Get all features whose bounding box intersects the provided extent. This
* method is intended for being called by the renderer. When null is returned,
* the renderer should not waste time rendering, and `opt_callback` is
* usually a function that requests a renderFrame, which will be called as soon
* as the data for `extent` is available.
*
* @param {ol.Extent} extent Bounding extent.
* @param {ol.Projection} projection Target projection.
* @param {ol.geom.GeometryType=} opt_type Optional geometry type.
* @return {Object.<string, ol.Feature>} Features.
* @param {Function=} opt_callback Callback to call when data is parsed.
* @return {Object.<string, ol.Feature>} Features or null if source is loading
* data for `extent`.
*/
ol.layer.Vector.prototype.getFeaturesObjectForExtent = function(extent,
opt_type) {
return this.featureCache_.getFeaturesObjectForExtent(extent, opt_type);
projection, opt_type, opt_callback) {
var source = this.getSource();
return source.prepareFeatures(this, extent, projection, opt_callback) ==
ol.source.VectorLoadState.LOADING ?
null :
this.featureCache_.getFeaturesObjectForExtent(extent, opt_type);
};
@@ -392,8 +423,6 @@ ol.layer.Vector.prototype.groupFeaturesBySymbolizerLiteral =
* one projection.
*/
ol.layer.Vector.prototype.parseFeatures = function(data, parser, projection) {
var features;
var lookup = {};
lookup[ol.geom.GeometryType.POINT] = this.pointVertices_;
lookup[ol.geom.GeometryType.LINESTRING] = this.lineVertices_;
@@ -406,8 +435,12 @@ ol.layer.Vector.prototype.parseFeatures = function(data, parser, projection) {
return lookup[type];
};
var addFeatures = function(features) {
var addFeatures = function(data) {
var features = data.features;
var sourceProjection = this.getSource().getProjection();
if (goog.isNull(sourceProjection)) {
sourceProjection = data.metadata.projection;
}
var transform = ol.proj.getTransform(sourceProjection, projection);
transform(
@@ -428,26 +461,28 @@ ol.layer.Vector.prototype.parseFeatures = function(data, parser, projection) {
this.addFeatures(features);
};
var options = {callback: callback};
var options = {callback: callback}, result;
if (goog.isString(data)) {
if (goog.isFunction(parser.readFeaturesFromStringAsync)) {
parser.readFeaturesFromStringAsync(data, goog.bind(addFeatures, this),
options);
} else {
goog.asserts.assert(goog.isFunction(parser.readFeaturesFromString),
'Expected a parser with readFeaturesFromString method.');
features = parser.readFeaturesFromString(data, options);
addFeatures.call(this, features);
goog.asserts.assert(
goog.isFunction(parser.readFeaturesFromString),
'Expected parser with a readFeaturesFromString method.');
result = parser.readFeaturesFromString(data, options);
addFeatures.call(this, result);
}
} else if (goog.isObject(data)) {
if (goog.isFunction(parser.readFeaturesFromObjectAsync)) {
parser.readFeaturesFromObjectAsync(data, goog.bind(addFeatures, this),
options);
} else {
goog.asserts.assert(goog.isFunction(parser.readFeaturesFromObject),
'Expected a parser with a readFeaturesFromObject method.');
features = parser.readFeaturesFromObject(data, options);
addFeatures.call(this, features);
goog.asserts.assert(
goog.isFunction(parser.readFeaturesFromObject),
'Expected parser with a readFeaturesFromObject method.');
result = parser.readFeaturesFromObject(data, options);
addFeatures.call(this, result);
}
} else {
// TODO: parse more data types
@@ -464,6 +499,29 @@ ol.layer.Vector.prototype.getTransformFeatureInfo = function() {
};
/**
* Remove features from the layer.
* @param {Array.<ol.Feature>} features Features to remove.
*/
ol.layer.Vector.prototype.removeFeatures = function(features) {
var extent = ol.extent.createEmpty(),
feature, geometry;
for (var i = 0, ii = features.length; i < ii; ++i) {
feature = features[i];
this.featureCache_.remove(feature);
geometry = feature.getGeometry();
if (!goog.isNull(geometry)) {
ol.extent.extend(extent, geometry.getBounds());
}
}
this.dispatchEvent(/** @type {ol.layer.VectorLayerEventObject} */ ({
extent: extent,
features: features,
type: goog.events.EventType.CHANGE
}));
};
/**
* @param {Array.<ol.Feature>} features Features.
* @return {string} Feature info.

View File

@@ -13,8 +13,6 @@ goog.require('goog.asserts');
goog.require('goog.async.AnimationDelay');
goog.require('goog.async.Delay');
goog.require('goog.debug.Console');
goog.require('goog.debug.Logger');
goog.require('goog.debug.Logger.Level');
goog.require('goog.dispose');
goog.require('goog.dom');
goog.require('goog.dom.TagName');
@@ -27,6 +25,8 @@ goog.require('goog.events.KeyHandler');
goog.require('goog.events.KeyHandler.EventType');
goog.require('goog.events.MouseWheelHandler');
goog.require('goog.events.MouseWheelHandler.EventType');
goog.require('goog.log');
goog.require('goog.log.Level');
goog.require('goog.object');
goog.require('goog.style');
goog.require('goog.vec.Mat4');
@@ -196,7 +196,7 @@ ol.Map = function(options) {
/**
* @private
* @type {?number}
* @type {goog.events.Key}
*/
this.viewPropertyListenerKey_ = null;
@@ -659,6 +659,11 @@ ol.Map.prototype.handleLayersRemove_ = function(collectionEvent) {
* @param {ol.MapBrowserEvent} mapBrowserEvent The event to handle.
*/
ol.Map.prototype.handleMapBrowserEvent = function(mapBrowserEvent) {
if (goog.isNull(this.frameState_)) {
// With no view defined, we cannot translate pixels into geographical
// coordinates so interactions cannot be used.
return;
}
mapBrowserEvent.frameState = this.frameState_;
var interactions = this.getInteractions();
var interactionsArray = /** @type {Array.<ol.interaction.Interaction>} */
@@ -667,8 +672,8 @@ ol.Map.prototype.handleMapBrowserEvent = function(mapBrowserEvent) {
if (this.dispatchEvent(mapBrowserEvent) !== false) {
for (i = interactionsArray.length - 1; i >= 0; i--) {
var interaction = interactionsArray[i];
interaction.handleMapBrowserEvent(mapBrowserEvent);
if (mapBrowserEvent.otherInteractionsStopped) {
var cont = interaction.handleMapBrowserEvent(mapBrowserEvent);
if (!cont) {
break;
}
}
@@ -1164,7 +1169,7 @@ ol.proj.addCommonProjections();
if (goog.DEBUG) {
(function() {
goog.debug.Console.autoInstall();
var logger = goog.debug.Logger.getLogger('ol');
logger.setLevel(goog.debug.Logger.Level.FINEST);
var logger = goog.log.getLogger('ol');
logger.setLevel(goog.log.Level.FINEST);
})();
}

View File

@@ -39,11 +39,6 @@ ol.MapBrowserEvent = function(type, map, browserEvent, opt_frameState) {
*/
this.coordinate_ = null;
/**
* @type {boolean}
*/
this.otherInteractionsStopped = false;
/**
* @private
* @type {ol.Pixel}
@@ -54,20 +49,6 @@ ol.MapBrowserEvent = function(type, map, browserEvent, opt_frameState) {
goog.inherits(ol.MapBrowserEvent, ol.MapEvent);
/**
* IE specific events.
* See http://msdn.microsoft.com/en-us/library/ie/hh673557(v=vs.85).aspx
* FIXME: replace with goog.events.EventType enum once we use
* goog/events/eventtype.js above r2211
* @enum {string}
*/
ol.MapBrowserEvent.IEEventType = {
MSPOINTERDOWN: 'MSPointerDown',
MSPOINTERMOVE: 'MSPointerMove',
MSPOINTERUP: 'MSPointerUp'
};
/**
* @return {ol.Coordinate} Coordinate.
*/
@@ -114,14 +95,6 @@ ol.MapBrowserEvent.prototype.preventDefault = function() {
};
/**
* Stop the interaction chain.
*/
ol.MapBrowserEvent.prototype.stopOtherInteractions = function() {
this.otherInteractionsStopped = true;
};
/**
* Prevents further propagation of the current event.
* @see https://developer.mozilla.org/en-US/docs/Web/API/event.stopPropagation
@@ -216,15 +189,15 @@ ol.MapBrowserEventHandler = function(map) {
this.touchListenerKeys_ = [
goog.events.listen(element, [
goog.events.EventType.TOUCHSTART,
ol.MapBrowserEvent.IEEventType.MSPOINTERDOWN
goog.events.EventType.MSPOINTERDOWN
], this.handleTouchStart_, false, this),
goog.events.listen(element, [
goog.events.EventType.TOUCHMOVE,
ol.MapBrowserEvent.IEEventType.MSPOINTERMOVE
goog.events.EventType.MSPOINTERMOVE
], this.handleTouchMove_, false, this),
goog.events.listen(element, [
goog.events.EventType.TOUCHEND,
ol.MapBrowserEvent.IEEventType.MSPOINTERUP
goog.events.EventType.MSPOINTERUP
], this.handleTouchEnd_, false, this)
];

View File

@@ -5,7 +5,6 @@
@exportProperty ol.Object.prototype.on
@exportProperty ol.Object.prototype.once
@exportProperty ol.Object.prototype.set
@exportProperty ol.Object.prototype.setOptions
@exportProperty ol.Object.prototype.setValues
@exportProperty ol.Object.prototype.un
@exportProperty ol.Object.prototype.unByKey

View File

@@ -118,7 +118,7 @@ ol.Object.getGetterName = function(key) {
/**
* @param {ol.Object} obj Object.
* @return {Object.<string, ?number>} Listeners.
* @return {Object.<string, goog.events.Key>} Listeners.
*/
ol.Object.getListeners = function(obj) {
return obj[ol.ObjectProperty.BINDINGS] ||
@@ -235,7 +235,7 @@ ol.Object.prototype.notifyInternal_ = function(key) {
* @param {Function} listener The listener function.
* @param {Object=} opt_scope Object is whose scope to call
* the listener.
* @return {?number} Unique key for the listener.
* @return {goog.events.Key} Unique key for the listener.
*/
ol.Object.prototype.on = function(type, listener, opt_scope) {
return goog.events.listen(this, type, listener, false, opt_scope);
@@ -248,7 +248,7 @@ ol.Object.prototype.on = function(type, listener, opt_scope) {
* @param {Function} listener The listener function.
* @param {Object=} opt_scope Object is whose scope to call
* the listener.
* @return {?number} Unique key for the listener.
* @return {goog.events.Key} Unique key for the listener.
*/
ol.Object.prototype.once = function(type, listener, opt_scope) {
return goog.events.listenOnce(this, type, listener, false, opt_scope);
@@ -281,12 +281,12 @@ ol.Object.prototype.set = function(key, value) {
/**
* Sets a collection of key-value pairs.
* @param {Object.<string, *>} options Options.
* @param {Object.<string, *>} values Values.
*/
ol.Object.prototype.setOptions = function(options) {
ol.Object.prototype.setValues = function(values) {
var key, value, setterName;
for (key in options) {
value = options[key];
for (key in values) {
value = values[key];
setterName = ol.Object.getSetterName(key);
if (this[setterName]) {
this[setterName](value);
@@ -297,13 +297,6 @@ ol.Object.prototype.setOptions = function(options) {
};
/**
* Sets a collection of key-value pairs.
* @param {Object.<string, *>} values Values.
*/
ol.Object.prototype.setValues = ol.Object.prototype.setOptions;
/**
* Removes a binding. Unbinding will set the unbound property to the current
* value. The object will not be notified, as the value has not changed.

View File

@@ -78,6 +78,12 @@ ol.Overlay = function(options) {
visible: true
};
/**
* @private
* @type {goog.events.Key}
*/
this.mapPostrenderListenerKey_ = null;
goog.events.listen(
this, ol.Object.getChangeEventType(ol.OverlayProperty.ELEMENT),
this.handleElementChanged, false, this);
@@ -280,7 +286,7 @@ ol.Overlay.prototype.updatePixelPosition_ = function() {
var position = this.getPosition();
if (!goog.isDef(map) || !map.isDef() || !goog.isDef(position)) {
if (this.rendered_.visible) {
goog.style.showElement(this.element_, false);
goog.style.setElementShown(this.element_, false);
this.rendered_.visible = false;
}
return;
@@ -329,7 +335,7 @@ ol.Overlay.prototype.updatePixelPosition_ = function() {
}
if (!this.rendered_.visible) {
goog.style.showElement(this.element_, true);
goog.style.setElementShown(this.element_, true);
this.rendered_.visible = true;
}

View File

@@ -18,7 +18,7 @@ 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.
* @return {ol.parser.ReadFeaturesResult} Features and metadata.
*/
ol.parser.DomFeatureParser.prototype.readFeaturesFromNode =
goog.abstractMethod;
@@ -34,7 +34,7 @@ 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.
* @return {ol.parser.ReadFeaturesResult} Features and metadata.
*/
ol.parser.ObjectFeatureParser.prototype.readFeaturesFromObject =
goog.abstractMethod;
@@ -50,7 +50,7 @@ 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.
* @return {ol.parser.ReadFeaturesResult} Features and metadata.
*/
ol.parser.StringFeatureParser.prototype.readFeaturesFromString =
goog.abstractMethod;
@@ -65,8 +65,8 @@ ol.parser.AsyncStringFeatureParser = function() {};
/**
* @param {string} data String data.
* @param {function(Array.<ol.Feature>)} callback Callback which is called
* after parsing.
* @param {function(ol.parser.ReadFeaturesResult)} callback Callback which is
* called after parsing.
* @param {ol.parser.ReadFeaturesOptions=} opt_options Feature reading options.
*/
ol.parser.AsyncStringFeatureParser.prototype.readFeaturesFromStringAsync =
@@ -82,8 +82,8 @@ ol.parser.AsyncObjectFeatureParser = function() {};
/**
* @param {Object} obj Object representing features.
* @param {function(Array.<ol.Feature>)} callback Callback which is called
* after parsing.
* @param {function(ol.parser.ReadFeaturesResult)} callback Callback which is
* called after parsing.
* @param {ol.parser.ReadFeaturesOptions=} opt_options Feature reading options.
*/
ol.parser.AsyncObjectFeatureParser.prototype.readFeaturesFromObjectAsync =
@@ -96,7 +96,20 @@ ol.parser.AsyncObjectFeatureParser.prototype.readFeaturesFromObjectAsync =
ol.parser.ReadFeaturesCallback;
/**
* @typedef {{projection: ol.ProjectionLike}}
*/
ol.parser.ReadFeaturesMetadata;
/**
* @typedef {{callback: ol.parser.ReadFeaturesCallback}}
*/
ol.parser.ReadFeaturesOptions;
/**
* @typedef {{features: Array.<ol.Feature>,
* metadata: ol.parser.ReadFeaturesMetadata}}
*/
ol.parser.ReadFeaturesResult;

View File

@@ -58,12 +58,13 @@ ol.parser.GeoJSON.read = function(str) {
* 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.
* @return {ol.parser.ReadFeaturesResult} Features and metadata.
*/
ol.parser.GeoJSON.prototype.readFeaturesFromString =
function(str, opt_options) {
var json = /** @type {GeoJSONFeatureCollection} */ (JSON.parse(str));
return this.parseFeatureCollection_(json, opt_options);
return {features: this.parseAsFeatureCollection_(json, opt_options),
metadata: {projection: 'EPSG:4326'}};
};
@@ -72,67 +73,86 @@ ol.parser.GeoJSON.prototype.readFeaturesFromString =
* @param {GeoJSONFeatureCollection} object GeoJSON feature collection decoded
* from JSON.
* @param {ol.parser.ReadFeaturesOptions=} opt_options Reader options.
* @return {Array.<ol.Feature>} Array of features.
* @return {ol.parser.ReadFeaturesResult} Features and metadata.
*/
ol.parser.GeoJSON.prototype.readFeaturesFromObject =
function(object, opt_options) {
return this.parseFeatureCollection_(object, opt_options);
return {features: this.parseAsFeatureCollection_(object, opt_options),
metadata: {projection: 'EPSG:4326'}};
};
/**
* Parse any GeoJSON object. Note that this method should not be called
* recursively due to the shared vertex creation.
*
* @param {GeoJSONObject} json GeoJSON object.
* @param {ol.parser.ReadFeaturesOptions=} opt_options Reader options.
* @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) {
ol.parser.GeoJSON.prototype.parse_ = function(json, opt_options) {
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);
if (json.type === 'FeatureCollection') {
result = this.parseFeatureCollection_(
/** @type {GeoJSONFeatureCollection} */ (json), opt_options);
} else if (json.type === 'Feature') {
result = this.parseFeature_(
/** @type {GeoJSONFeature} */ (json), opt_options);
} else if (json.type === 'GeometryCollection') {
result = this.parseGeometryCollection_(
/** @type {GeoJSONGeometryCollection} */ (json), opt_options);
} else {
// we've been called with a geometry or an unknown object
// create a feature to get shared vertices handling
var feature = this.parseFeature_(
/** @type {GeoJSONFeature} */ ({type: 'Feature', geometry: json}),
opt_options);
result = feature.getGeometry();
}
return result;
};
/**
* @param {GeoJSONObject} json GeoJSON object.
* @param {ol.parser.ReadFeaturesOptions=} opt_options Reader options.
* @return {Array.<ol.Feature>} Parsed object coerced into array of features.
* @private
*/
ol.parser.GeoJSON.prototype.parseAsFeatureCollection_ = function(json,
opt_options) {
var obj = this.parse_(json, opt_options);
var features = [];
var feature;
if (obj instanceof ol.Feature) {
features = [obj];
} else if (obj instanceof ol.geom.Geometry) {
feature = new ol.Feature();
feature.setGeometry(obj);
features = [feature];
} else if (goog.isArray(obj)) {
var item, geomArray;
for (var i = 0, ii = obj.length; i < ii; ++i) {
item = obj[i];
geomArray = geomArray || (item instanceof ol.geom.Geometry);
if (!geomArray) {
goog.asserts.assert(item instanceof ol.Feature, 'expected feature');
features = obj;
break;
} else {
feature = new ol.Feature();
feature.setGeometry(item);
features[i] = feature;
}
}
}
return features;
};
/**
* @param {GeoJSONFeature} json GeoJSON feature.
* @param {ol.parser.ReadFeaturesOptions=} opt_options Read options.
@@ -207,17 +227,20 @@ ol.parser.GeoJSON.prototype.parseFeatureCollection_ = function(
/**
* @param {GeoJSONGeometryCollection} json GeoJSON geometry collection.
* @param {ol.parser.ReadFeaturesOptions=} opt_options Read options.
* @return {Array.<ol.geom.Geometry>} Parsed array of geometries.
* @private
*/
ol.parser.GeoJSON.prototype.parseGeometryCollection_ = function(json) {
ol.parser.GeoJSON.prototype.parseGeometryCollection_ = function(json,
opt_options) {
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]));
result[i] = this.parse_(/** @type {GeoJSONGeometry} */ (geometries[i]),
opt_options);
}
return result;
};

View File

@@ -234,7 +234,7 @@ goog.inherits(ol.parser.GPX, ol.parser.XML);
/**
* @param {string|Document|Element|Object} data Data to read.
* @return {Object} An object representing the document.
* @return {ol.parser.ReadFeaturesResult} An object representing the document.
*/
ol.parser.GPX.prototype.read = function(data) {
if (goog.isString(data)) {
@@ -243,7 +243,8 @@ ol.parser.GPX.prototype.read = function(data) {
if (data && data.nodeType == 9) {
data = data.documentElement;
}
var obj = {};
var obj = /** @type {ol.parser.ReadFeaturesResult} */
({metadata: {projection: 'EPSG:4326'}});
this.readNode(data, obj);
return obj;
};
@@ -253,12 +254,12 @@ ol.parser.GPX.prototype.read = function(data) {
* Parse a GPX document provided as a string.
* @param {string} str GPX document.
* @param {ol.parser.ReadFeaturesOptions=} opt_options Reader options.
* @return {Array.<ol.Feature>} Array of features.
* @return {ol.parser.ReadFeaturesResult} Features and metadata.
*/
ol.parser.GPX.prototype.readFeaturesFromString =
function(str, opt_options) {
this.readFeaturesOptions_ = opt_options;
return this.read(str).features;
return this.read(str);
};
@@ -266,24 +267,24 @@ ol.parser.GPX.prototype.readFeaturesFromString =
* Parse a GPX document provided as a DOM structure.
* @param {Element|Document} node Document or element node.
* @param {ol.parser.ReadFeaturesOptions=} opt_options Feature reading options.
* @return {Array.<ol.Feature>} Array of features.
* @return {ol.parser.ReadFeaturesResult} Features and metadata.
*/
ol.parser.GPX.prototype.readFeaturesFromNode =
function(node, opt_options) {
this.readFeaturesOptions_ = opt_options;
return this.read(node).features;
return this.read(node);
};
/**
* @param {Object} obj Object representing features.
* @param {ol.parser.ReadFeaturesOptions=} opt_options Feature reading options.
* @return {Array.<ol.Feature>} Array of features.
* @return {ol.parser.ReadFeaturesResult} Features and metadata.
*/
ol.parser.GPX.prototype.readFeaturesFromObject =
function(obj, opt_options) {
this.readFeaturesOptions_ = opt_options;
return this.read(obj).features;
return this.read(obj);
};

View File

@@ -184,24 +184,25 @@ ol.parser.KML = function(opt_options) {
var buckets = goog.array.bucket(parts, function(val) {
return val.type;
});
// homogeneous collection
var obj = {};
if (goog.object.getCount(buckets) === 1) {
// homogeneous collection
var type = goog.object.getAnyKey(buckets);
switch (type) {
case ol.geom.GeometryType.POINT:
container.geometry = {
obj.geometry = {
type: ol.geom.GeometryType.MULTIPOINT,
parts: parts
};
break;
case ol.geom.GeometryType.LINESTRING:
container.geometry = {
obj.geometry = {
type: ol.geom.GeometryType.MULTILINESTRING,
parts: parts
};
break;
case ol.geom.GeometryType.POLYGON:
container.geometry = {
obj.geometry = {
type: ol.geom.GeometryType.MULTIPOLYGON,
parts: parts
};
@@ -210,11 +211,18 @@ ol.parser.KML = function(opt_options) {
break;
}
} else {
container.geometry = {
// mixed collection
obj.geometry = {
type: ol.geom.GeometryType.GEOMETRYCOLLECTION,
parts: parts
};
}
if (goog.isArray(container)) {
// MultiGeometry nested inside another
container.push(obj.geometry);
} else {
container.geometry = obj.geometry;
}
},
'Point': function(node, container) {
var coordinates = [];
@@ -334,7 +342,7 @@ ol.parser.KML = function(opt_options) {
this.readChildNodes(node, symbolizer);
if (symbolizer.color) {
symbolizer.strokeColor = symbolizer.color.color;
symbolizer.opacity = symbolizer.color.opacity;
symbolizer.strokeOpacity = symbolizer.color.opacity;
}
if (symbolizer.width) {
symbolizer.strokeWidth = parseFloat(symbolizer.width);
@@ -345,30 +353,31 @@ ol.parser.KML = function(opt_options) {
obj['symbolizers'].push(new ol.style.Line(symbolizer));
},
'PolyStyle': function(node, obj) {
var symbolizer = {};
this.readChildNodes(node, symbolizer);
if (symbolizer.color) {
symbolizer.fillColor = symbolizer.color.color;
var style = {}; // from KML
var symbolizer = {}; // for ol.style.Polygon
this.readChildNodes(node, style);
// check if poly has fill
if (!(style.fill === '0' || style.fill === 'false')) {
if (style.color) {
symbolizer.fillColor = style.color.color;
symbolizer.fillOpacity = style.color.opacity;
} else {
// KML defaults
symbolizer.fillColor = '#ffffff';
symbolizer.fillOpacity = 1;
}
}
if (symbolizer.fill === '0' || symbolizer.fill === 'false') {
// TODO we need a better way in the symbolizer to disable fill
// now we are using opacity for this, but it's a workaround
// see also: https://github.com/openlayers/ol3/issues/475
symbolizer.opacity = 0;
} else {
symbolizer.opacity = symbolizer.color.opacity;
// check if poly has stroke
if (!(style.outline === '0' || style.outline === 'false')) {
if (style.color) {
symbolizer.strokeColor = style.color.color;
symbolizer.strokeOpacity = style.color.opacity;
} else {
// KML defaults
symbolizer.strokeColor = '#ffffff';
symbolizer.strokeOpacity = 1;
}
}
if (symbolizer.width) {
symbolizer.strokeWidth = parseFloat(symbolizer.width);
}
// outline disabled
if (symbolizer.outline === '0' || symbolizer.outline === 'false') {
symbolizer.strokeWidth = 0;
}
delete symbolizer.outline;
delete symbolizer.width;
delete symbolizer.color;
delete symbolizer.fill;
obj['ids'].push(node.getAttribute('id'));
obj['symbolizers'].push(new ol.style.Polygon(symbolizer));
},
@@ -615,6 +624,11 @@ ol.parser.KML = function(opt_options) {
}
},
'PolyStyle': function(symbolizerObj) {
/**
* There is not a 1:1 mapping between KML PolyStyle and
* ol.style.Polygon. In KML, if a PolyStyle has <outline>1</outline>
* then the "current" LineStyle is used to stroke the polygon.
*/
var node = this.createElementNS('PolyStyle');
if (symbolizerObj.id) {
this.setAttributeNS(node, null, 'id', symbolizerObj.id);
@@ -622,16 +636,27 @@ ol.parser.KML = function(opt_options) {
var symbolizer = symbolizerObj.symbolizer;
var literal = symbolizer instanceof ol.style.PolygonLiteral ?
symbolizer : symbolizer.createLiteral();
if (literal.opacity !== 0) {
var color, opacity;
if (literal.fillOpacity !== 0) {
this.writeNode('fill', '1', null, node);
color = literal.fillColor;
opacity = literal.fillOpacity;
} else {
this.writeNode('fill', '0', null, node);
}
this.writeNode('color', {
color: literal.fillColor.substring(1),
opacity: literal.opacity
}, null, node);
this.writeNode('width', literal.strokeWidth, null, node);
if (literal.strokeOpacity) {
this.writeNode('outline', '1', null, node);
color = color || literal.strokeColor;
opacity = opacity || literal.strokeOpacity;
} else {
this.writeNode('outline', '0', null, node);
}
if (color && opacity) {
this.writeNode('color', {
color: color.substring(1),
opacity: opacity
}, null, node);
}
return node;
},
'fill': function(fill) {
@@ -639,6 +664,11 @@ ol.parser.KML = function(opt_options) {
node.appendChild(this.createTextNode(fill));
return node;
},
'outline': function(outline) {
var node = this.createElementNS('outline');
node.appendChild(this.createTextNode(outline));
return node;
},
'LineStyle': function(symbolizerObj) {
var node = this.createElementNS('LineStyle');
if (symbolizerObj.id) {
@@ -649,7 +679,7 @@ ol.parser.KML = function(opt_options) {
symbolizer : symbolizer.createLiteral();
this.writeNode('color', {
color: literal.strokeColor.substring(1),
opacity: literal.opacity
opacity: literal.strokeOpacity
}, null, node);
this.writeNode('width', literal.strokeWidth, null, node);
return node;
@@ -755,6 +785,10 @@ ol.parser.KML = function(opt_options) {
return node;
},
'Polygon': function(geometry) {
/**
* KML doesn't specify the winding order of coordinates in linear
* rings. So we keep them as they are in the geometries.
*/
var node = this.createElementNS('Polygon');
var coordinates = geometry.getCoordinates();
this.writeNode('outerBoundaryIs', coordinates[0], null, node);
@@ -809,8 +843,8 @@ goog.inherits(ol.parser.KML, ol.parser.XML);
/**
* @param {Object} obj Object representing features.
* @param {function(Array.<ol.Feature>)} callback Callback which is called
* after parsing.
* @param {function(ol.parser.ReadFeaturesResult)} callback Callback which is
* called after parsing.
* @param {ol.parser.ReadFeaturesOptions=} opt_options Feature reading options.
*/
ol.parser.KML.prototype.readFeaturesFromObjectAsync =
@@ -821,9 +855,9 @@ ol.parser.KML.prototype.readFeaturesFromObjectAsync =
/**
* @param {string} str KML document.
* @param {function(Array.<ol.Feature>)} callback Callback which is called
* after parsing.
* @param {string} str String data.
* @param {function(ol.parser.ReadFeaturesResult)}
* callback Callback which is called after parsing.
* @param {ol.parser.ReadFeaturesOptions=} opt_options Feature reading options.
*/
ol.parser.KML.prototype.readFeaturesFromStringAsync =
@@ -837,12 +871,12 @@ ol.parser.KML.prototype.readFeaturesFromStringAsync =
* Parse a KML document provided as a string.
* @param {string} str KML document.
* @param {ol.parser.ReadFeaturesOptions=} opt_options Reader options.
* @return {Array.<ol.Feature>} Array of features.
* @return {ol.parser.ReadFeaturesResult} Features and metadata.
*/
ol.parser.KML.prototype.readFeaturesFromString =
function(str, opt_options) {
this.readFeaturesOptions_ = opt_options;
return this.read(str).features;
return /** @type {ol.parser.ReadFeaturesResult} */ (this.read(str));
};
@@ -850,24 +884,24 @@ ol.parser.KML.prototype.readFeaturesFromString =
* Parse a KML document provided as a DOM structure.
* @param {Element|Document} node Document or element node.
* @param {ol.parser.ReadFeaturesOptions=} opt_options Feature reading options.
* @return {Array.<ol.Feature>} Array of features.
* @return {ol.parser.ReadFeaturesResult} Features and metadata.
*/
ol.parser.KML.prototype.readFeaturesFromNode =
function(node, opt_options) {
this.readFeaturesOptions_ = opt_options;
return this.read(node).features;
return /** @type {ol.parser.ReadFeaturesResult} */ (this.read(node));
};
/**
* @param {Object} obj Object representing features.
* @param {ol.parser.ReadFeaturesOptions=} opt_options Feature reading options.
* @return {Array.<ol.Feature>} Array of features.
* @return {ol.parser.ReadFeaturesResult} Features and metadata.
*/
ol.parser.KML.prototype.readFeaturesFromObject =
function(obj, opt_options) {
this.readFeaturesOptions_ = opt_options;
return this.read(obj).features;
return /** @type {ol.parser.ReadFeaturesResult} */ (this.read(obj));
};
@@ -918,9 +952,11 @@ ol.parser.KML.prototype.parseLinks = function(deferreds, obj, done) {
/**
* @param {string|Document|Element|Object} data Data to read.
* @param {Function=} opt_callback Optional callback to call when reading
* is done.
* @return {Object} An object representing the document.
* @param {function(ol.parser.ReadFeaturesResult)=} opt_callback Optional
* callback to call when reading is done. If provided, this method will
* return undefined.
* @return {ol.parser.ReadFeaturesResult|undefined} An object representing the
* document if `opt_callback` was not provided.
*/
ol.parser.KML.prototype.read = function(data, opt_callback) {
if (goog.isString(data)) {
@@ -929,7 +965,8 @@ ol.parser.KML.prototype.read = function(data, opt_callback) {
if (data && data.nodeType == 9) {
data = data.documentElement;
}
var obj = {};
var obj = /** @type {ol.parser.ReadFeaturesResult} */
({metadata: {projection: 'EPSG:4326'}});
this.readNode(data, obj);
if (goog.isDef(opt_callback)) {
var deferreds = [];
@@ -943,7 +980,7 @@ ol.parser.KML.prototype.read = function(data, opt_callback) {
var feature = obj.features[i];
this.applyStyle_(feature, obj['styles']);
}
opt_callback.call(null, obj.features);
opt_callback.call(null, obj);
}, function() {
throw new Error('KML: parsing of NetworkLinks failed');
}, this);
@@ -951,7 +988,6 @@ ol.parser.KML.prototype.read = function(data, opt_callback) {
} else {
return obj;
}
return null;
};
@@ -1020,7 +1056,7 @@ ol.parser.KML.prototype.createGeometry_ = function(container,
for (i = 0, ii = container.geometry.parts.length; i < ii; i++) {
coordinates.push(container.geometry.parts[i].coordinates);
}
geometry = ol.geom.MultiPoint.fromParts(coordinates, opt_vertices);
geometry = new ol.geom.MultiPoint(coordinates, opt_vertices);
break;
case ol.geom.GeometryType.MULTILINESTRING:
coordinates = [];
@@ -1034,7 +1070,7 @@ ol.parser.KML.prototype.createGeometry_ = function(container,
for (i = 0, ii = container.geometry.parts.length; i < ii; i++) {
coordinates.push(container.geometry.parts[i].coordinates);
}
geometry = ol.geom.MultiPolygon.fromParts(coordinates, opt_vertices);
geometry = new ol.geom.MultiPolygon(coordinates, opt_vertices);
break;
case ol.geom.GeometryType.GEOMETRYCOLLECTION:
var geometries = [];

View File

@@ -1,5 +1,6 @@
goog.provide('ol.parser.ogc.GML');
goog.require('goog.array');
goog.require('goog.asserts');
goog.require('goog.dom.xml');
goog.require('ol.Feature');
goog.require('ol.geom.Geometry');
@@ -14,6 +15,7 @@ goog.require('ol.geom.Point');
goog.require('ol.geom.Polygon');
goog.require('ol.parser.StringFeatureParser');
goog.require('ol.parser.XML');
goog.require('ol.proj');
@@ -27,8 +29,6 @@ goog.require('ol.parser.XML');
ol.parser.ogc.GML = function(opt_options) {
var options = /** @type {ol.parser.GMLOptions} */
(goog.isDef(opt_options) ? opt_options : {});
this.axisOrientation = goog.isDef(options.axisOrientation) ?
options.axisOrientation : 'enu';
this.extractAttributes = goog.isDef(options.extractAttributes) ?
options.extractAttributes : true;
this.surface = goog.isDef(options.surface) ?
@@ -39,8 +39,21 @@ ol.parser.ogc.GML = function(opt_options) {
options.multiCurve : true;
this.multiSurface = goog.isDef(options.multiSurface) ?
options.multiSurface : true;
this.srsName = goog.isDef(options.srsName) ?
options.srsName : null;
this.readOptions = options.readOptions;
this.writeOptions = options.writeOptions;
/**
* @protected
* @type {string|undefined}
*/
this.srsName;
/**
* @protected
* @type {string|undefined}
*/
this.axisOrientation;
if (goog.isDef(options.schemaLocation)) {
this.schemaLocation = options.schemaLocation;
}
@@ -61,7 +74,18 @@ ol.parser.ogc.GML = function(opt_options) {
},
'http://www.opengis.net/gml': {
'_inherit': function(node, obj, container) {
// To be implemented by version specific parsers
// Version specific parsers extend this with goog.functions.sequence
var srsName;
if (!goog.isDef(this.srsName)) {
srsName = this.srsName = node.getAttribute('srsName');
}
if (!goog.isDef(this.axisOrientation)) {
if (goog.isDefAndNotNull(srsName)) {
this.axisOrientation = ol.proj.get(srsName).getAxisOrientation();
} else {
this.axisOrientation = 'enu';
}
}
},
'name': function(node, obj) {
obj.name = this.getChildValue(node);
@@ -126,6 +150,8 @@ ol.parser.ogc.GML = function(opt_options) {
},
'Point': function(node, container) {
var coordinates = [];
this.readers[this.defaultNamespaceURI]['_inherit'].apply(this,
[node, coordinates, container]);
this.readChildNodes(node, coordinates);
var point = {
type: ol.geom.GeometryType.POINT,
@@ -315,9 +341,9 @@ ol.parser.ogc.GML = function(opt_options) {
}
this.writers = {
'http://www.opengis.net/gml': {
'featureMember': function(feature) {
'featureMember': function(obj) {
var node = this.createElementNS('gml:featureMember');
this.writeNode('_typeName', feature, this.featureNS, node);
this.writeNode('_typeName', obj, this.featureNS, node);
return node;
},
'MultiPoint': function(geometry) {
@@ -455,17 +481,38 @@ goog.inherits(ol.parser.ogc.GML, ol.parser.XML);
/**
* @param {string|Document|Element|Object} data Data to read.
* @return {Object} An object representing the document.
* @param {ol.parser.GMLReadOptions=} opt_options Read options.
* @return {ol.parser.ReadFeaturesResult} An object representing the document.
*/
ol.parser.ogc.GML.prototype.read = function(data) {
ol.parser.ogc.GML.prototype.read = function(data, opt_options) {
var srsName;
if (goog.isDef(opt_options) && goog.isDef(opt_options.srsName)) {
srsName = opt_options.srsName;
} else if (goog.isDef(this.readOptions) &&
goog.isDef(this.readOptions.srsName)) {
srsName = this.readOptions.srsName;
}
if (goog.isDef(srsName)) {
this.srsName = goog.isString(srsName) ? srsName : srsName.getCode();
}
if (goog.isDef(opt_options) && goog.isDef(opt_options.axisOrientation)) {
this.axisOrientation = opt_options.axisOrientation;
} else if (goog.isDef(this.readOptions) &&
goog.isDef(this.readOptions.axisOrientation)) {
this.axisOrientation = this.readOptions.axisOrientation;
}
if (typeof data == 'string') {
data = goog.dom.xml.loadXml(data);
}
if (data && data.nodeType == 9) {
data = data.documentElement;
}
var obj = {features: []};
var obj = /** @type {ol.parser.ReadFeaturesResult} */
({features: [], metadata: {}});
this.readNode(data, obj, true);
obj.metadata.projection = this.srsName;
delete this.srsName;
delete this.axisOrientation;
return obj;
};
@@ -569,10 +616,41 @@ ol.parser.ogc.GML.prototype.createGeometry = function(container,
* Parse a GML document provided as a string.
* @param {string} str GML document.
* @param {ol.parser.ReadFeaturesOptions=} opt_options Reader options.
* @return {Array.<ol.Feature>} Array of features.
* @return {ol.parser.ReadFeaturesResult} Features and metadata.
*/
ol.parser.ogc.GML.prototype.readFeaturesFromString =
function(str, opt_options) {
this.readFeaturesOptions_ = opt_options;
return this.read(str).features;
return this.read(str);
};
/**
* Applies the writeOptions passed into the write function.
* @param {ol.parser.ReadFeaturesResult} obj Object structure to write out as
* GML.
* @param {ol.parser.GMLWriteOptions=} opt_options Write options.
*/
ol.parser.ogc.GML.prototype.applyWriteOptions = function(obj, opt_options) {
// srsName handling: opt_options -> this.writeOptions -> obj.metadata
var srsName;
if (goog.isDef(opt_options) && goog.isDef(opt_options.srsName)) {
srsName = opt_options.srsName;
} else if (goog.isDef(this.writeOptions) &&
goog.isDef(this.writeOptions.srsName)) {
srsName = this.writeOptions.srsName;
} else if (goog.isDef(obj.metadata)) {
srsName = obj.metadata.projection;
}
goog.asserts.assert(goog.isDef(srsName), 'srsName required for writing GML');
this.srsName = goog.isString(srsName) ? srsName : srsName.getCode();
// axisOrientation handling: opt_options -> this.writeOptions
if (goog.isDef(opt_options) && goog.isDef(opt_options.axisOrientation)) {
this.axisOrientation = opt_options.axisOrientation;
} else if (goog.isDef(this.writeOptions) &&
goog.isDef(this.writeOptions.axisOrientation)) {
this.axisOrientation = this.writeOptions.axisOrientation;
} else {
this.axisOrientation = ol.proj.get(this.srsName).getAxisOrientation();
}
};

View File

@@ -28,6 +28,8 @@ ol.parser.ogc.GML_v2 = function(opt_options) {
},
'Box': function(node, container) {
var coordinates = [];
this.readers[this.defaultNamespaceURI]['_inherit'].apply(this,
[node, coordinates, container]);
this.readChildNodes(node, coordinates);
container.projection = node.getAttribute('srsName');
container.bounds = [coordinates[0][0][0], coordinates[0][1][0],
@@ -68,9 +70,17 @@ ol.parser.ogc.GML_v2 = function(opt_options) {
'Polygon': function(geometry) {
var node = this.createElementNS('gml:Polygon');
var coordinates = geometry.getCoordinates();
this.writeNode('outerBoundaryIs', coordinates[0], null, node);
/**
* Though there continues to be ambiguity around this, GML references
* ISO 19107, which says polygons have counter-clockwise exterior rings
* and clockwise interior rings. The ambiguity comes because the
* the Simple Feature Access - SQL spec (ISO 19125-2) says that no
* winding order is enforced. Anyway, we write out counter-clockwise
* exterior and clockwise interior here but accept either when reading.
*/
this.writeNode('outerBoundaryIs', coordinates[0].reverse(), null, node);
for (var i = 1; i < coordinates.length; ++i) {
this.writeNode('innerBoundaryIs', coordinates[i], null, node);
this.writeNode('innerBoundaryIs', coordinates[i].reverse(), null, node);
}
return node;
},
@@ -105,14 +115,20 @@ goog.inherits(ol.parser.ogc.GML_v2, ol.parser.ogc.GML);
/**
* @param {Object} obj Object structure to write out as XML.
* @return {string} An string representing the XML document.
* @param {ol.parser.ReadFeaturesResult} obj Object structure to write out as
* GML.
* @param {ol.parser.GMLWriteOptions=} opt_options Write options.
* @return {string} A string representing the GML document.
*/
ol.parser.ogc.GML_v2.prototype.write = function(obj) {
ol.parser.ogc.GML_v2.prototype.write = function(obj, opt_options) {
this.applyWriteOptions(obj, opt_options);
var root = this.writeNode('FeatureCollection', obj.features,
'http://www.opengis.net/wfs');
this.setAttributeNS(
root, 'http://www.w3.org/2001/XMLSchema-instance',
'xsi:schemaLocation', this.schemaLocation);
return this.serialize(root);
var gml = this.serialize(root);
delete this.srsName;
delete this.axisOrientation;
return gml;
};

View File

@@ -1,6 +1,7 @@
goog.provide('ol.parser.ogc.GML_v3');
goog.require('goog.array');
goog.require('goog.functions');
goog.require('goog.object');
goog.require('ol.geom.GeometryType');
goog.require('ol.parser.ogc.GML');
@@ -61,14 +62,16 @@ ol.parser.ogc.GML_v3 = function(opt_options) {
return node;
};
goog.object.extend(this.readers['http://www.opengis.net/gml'], {
'_inherit': function(node, obj, container) {
// SRSReferenceGroup attributes
var dim = parseInt(node.getAttribute('srsDimension'), 10) ||
(container && container.srsDimension);
if (dim) {
obj.srsDimension = dim;
}
},
'_inherit': goog.functions.sequence(
this.readers['http://www.opengis.net/gml']['_inherit'],
function(node, obj, container) {
// SRSReferenceGroup attributes
var dim = parseInt(node.getAttribute('srsDimension'), 10) ||
(container && container.srsDimension);
if (dim) {
obj.srsDimension = dim;
}
}),
'featureMembers': function(node, obj) {
this.readChildNodes(node, obj);
},
@@ -205,6 +208,8 @@ ol.parser.ogc.GML_v3 = function(opt_options) {
},
'Envelope': function(node, container) {
var coordinates = [];
this.readers[this.defaultNamespaceURI]['_inherit'].apply(this,
[node, coordinates, container]);
this.readChildNodes(node, coordinates);
container.projection = node.getAttribute('srsName');
container.bounds = [coordinates[0][0][0][0], coordinates[1][0][0][0],
@@ -299,18 +304,26 @@ ol.parser.ogc.GML_v3 = function(opt_options) {
var node = this.createElementNS('gml:PolygonPatch');
node.setAttribute('interpolation', 'planar');
var coordinates = geometry.getCoordinates();
this.writeNode('exterior', coordinates[0], null, node);
this.writeNode('exterior', coordinates[0].reverse(), null, node);
for (var i = 1, len = coordinates.length; i < len; ++i) {
this.writeNode('interior', coordinates[i], null, node);
this.writeNode('interior', coordinates[i].reverse(), null, node);
}
return node;
},
'Polygon': function(geometry) {
var node = this.createElementNS('gml:Polygon');
var coordinates = geometry.getCoordinates();
this.writeNode('exterior', coordinates[0], null, node);
/**
* Though there continues to be ambiguity around this, GML references
* ISO 19107, which says polygons have counter-clockwise exterior rings
* and clockwise interior rings. The ambiguity comes because the
* the Simple Feature Access - SQL spec (ISO 19125-2) says that no
* winding order is enforced. Anyway, we write out counter-clockwise
* exterior and clockwise interior here but accept either when reading.
*/
this.writeNode('exterior', coordinates[0].reverse(), null, node);
for (var i = 1, len = coordinates.length; i < len; ++i) {
this.writeNode('interior', coordinates[i], null, node);
this.writeNode('interior', coordinates[i].reverse(), null, node);
}
return node;
},
@@ -366,7 +379,7 @@ ol.parser.ogc.GML_v3 = function(opt_options) {
this.writeNode('lowerCorner', bounds, null, node);
this.writeNode('upperCorner', bounds, null, node);
// srsName attribute is required for gml:Envelope
if (this.srsName) {
if (goog.isDef(this.srsName)) {
node.setAttribute('srsName', this.srsName);
}
return node;
@@ -401,13 +414,19 @@ goog.inherits(ol.parser.ogc.GML_v3, ol.parser.ogc.GML);
/**
* @param {Object} obj Object structure to write out as XML.
* @param {ol.parser.ReadFeaturesResult} obj Object structure to write out as
* XML.
* @param {ol.parser.GMLWriteOptions=} opt_options Write options.
* @return {string} An string representing the XML document.
*/
ol.parser.ogc.GML_v3.prototype.write = function(obj) {
ol.parser.ogc.GML_v3.prototype.write = function(obj, opt_options) {
this.applyWriteOptions(obj, opt_options);
var root = this.writeNode('featureMembers', obj.features);
this.setAttributeNS(
root, 'http://www.w3.org/2001/XMLSchema-instance',
'xsi:schemaLocation', this.schemaLocation);
return this.serialize(root);
var gml = this.serialize(root);
delete this.srsName;
delete this.axisOrientation;
return gml;
};

View File

@@ -0,0 +1,4 @@
@exportSymbol ol.parser.TopoJSON
@exportProperty ol.parser.TopoJSON.prototype.read
@exportProperty ol.parser.TopoJSON.read

441
src/ol/parser/topojson.js Normal file
View File

@@ -0,0 +1,441 @@
goog.provide('ol.parser.TopoJSON');
goog.require('ol.Feature');
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.Vertex');
goog.require('ol.geom.VertexArray');
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.TopoJSON = function() {
/**
* Common feature for all shared vertex creation.
* // TODO: make feature optional in shared vertex callback
*
* @type {ol.Feature}
* @private
*/
this.feature_ = new ol.Feature();
};
goog.inherits(ol.parser.TopoJSON, ol.parser.Parser);
goog.addSingletonGetter(ol.parser.TopoJSON);
/**
* Concatenate arcs into a coordinate array.
* @param {Array.<number>} indices Indices of arcs to concatenate. Negative
* values indicate arcs need to be reversed.
* @param {Array.<ol.geom.VertexArray>} arcs Arcs (already transformed).
* @return {ol.geom.VertexArray} Coordinate array.
* @private
*/
ol.parser.TopoJSON.prototype.concatenateArcs_ = function(indices, arcs) {
var coordinates = [];
var index, arc;
for (var i = 0, ii = indices.length; i < ii; ++i) {
index = indices[i];
if (i > 0) {
// splicing together arcs, discard last point
coordinates.pop();
}
if (index >= 0) {
// forward arc
arc = arcs[index];
} else {
// reverse arc
arc = arcs[~index].slice().reverse();
}
coordinates.push.apply(coordinates, arc);
}
return coordinates;
};
/**
* Parse a TopoJSON string.
* @param {string} str TopoJSON string.
* @return {Array.<ol.Feature>} Array of features.
*/
ol.parser.TopoJSON.prototype.read = function(str) {
var topology = /** @type {TopoJSONTopology} */ (JSON.parse(str));
return this.readFeaturesFromObject(topology).features;
};
/**
* Create features from a TopoJSON topology string.
*
* @param {string} str TopoJSON topology string.
* @param {ol.parser.ReadFeaturesOptions=} opt_options Reader options.
* @return {ol.parser.ReadFeaturesResult} Features and metadata.
*/
ol.parser.TopoJSON.prototype.readFeaturesFromString =
function(str, opt_options) {
var topology = /** @type {TopoJSONTopology} */ (JSON.parse(str));
if (topology.type !== 'Topology') {
throw new Error('Not a "Topology" type object');
}
return {features: this.readFeaturesFromTopology_(topology, opt_options),
metadata: {projection: 'EPSG:4326'}};
};
/**
* Create features from a TopoJSON topology object.
*
* @param {TopoJSONTopology} topology TopoJSON topology object.
* @param {ol.parser.ReadFeaturesOptions=} opt_options Reader options.
* @return {ol.parser.ReadFeaturesResult} Features and metadata.
*/
ol.parser.TopoJSON.prototype.readFeaturesFromObject =
function(topology, opt_options) {
if (topology.type !== 'Topology') {
throw new Error('Not a "Topology" type object');
}
return {features: this.readFeaturesFromTopology_(topology, opt_options),
metadata: {projection: 'EPSG:4326'}};
};
/**
* Create a feature from a TopoJSON geometry object.
*
* @param {TopoJSONGeometry} object TopoJSON geometry object.
* @param {Array.<ol.geom.VertexArray>} arcs Array of arcs.
* @param {Array.<number>} scale Scale for each dimension.
* @param {Array.<number>} translate Translation for each dimension.
* @param {ol.parser.ReadFeaturesOptions=} opt_options Reader options.
* @return {ol.Feature} Feature.
* @private
*/
ol.parser.TopoJSON.prototype.readFeatureFromGeometry_ = function(object, arcs,
scale, translate, opt_options) {
var geometry;
var type = object.type;
if (type === 'Point') {
geometry = this.readPoint_(/** @type {TopoJSONPoint} */ (object), scale,
translate, opt_options);
} else if (type === 'LineString') {
geometry = this.readLineString_(/** @type {TopoJSONLineString} */ (object),
arcs, opt_options);
} else if (type === 'Polygon') {
geometry = this.readPolygon_(/** @type {TopoJSONPolygon} */ (object), arcs,
opt_options);
} else if (type === 'MultiPoint') {
geometry = this.readMultiPoint_(/** @type {TopoJSONMultiPoint} */ (object),
scale, translate, opt_options);
} else if (type === 'MultiLineString') {
geometry = this.readMultiLineString_(
/** @type {TopoJSONMultiLineString} */(object), arcs, opt_options);
} else if (type === 'MultiPolygon') {
geometry = this.readMultiPolygon_(
/** @type {TopoJSONMultiPolygon} */ (object), arcs, opt_options);
} else {
throw new Error('Unsupported geometry type: ' + type);
}
var feature = new ol.Feature();
feature.setGeometry(geometry);
if (goog.isDef(object.id)) {
feature.setFeatureId(String(object.id));
}
return feature;
};
/**
* Create features from a TopoJSON GeometryCollection object.
*
* @param {TopoJSONGeometryCollection} collection TopoJSON GeometryCollection
* object.
* @param {Array.<ol.geom.VertexArray>} arcs Array of arcs.
* @param {Array.<number>} scale Scale for each dimension.
* @param {Array.<number>} translate Translation for each dimension.
* @param {ol.parser.ReadFeaturesOptions=} opt_options Reader options.
* @return {Array.<ol.Feature>} Array of features.
* @private
*/
ol.parser.TopoJSON.prototype.readFeaturesFromGeometryCollection_ = function(
collection, arcs, scale, translate, opt_options) {
var geometries = collection.geometries;
var num = geometries.length;
var features = new Array(num);
for (var i = 0; i < num; ++i) {
features[i] = this.readFeatureFromGeometry_(geometries[i], arcs, scale,
translate, opt_options);
}
return features;
};
/**
* @param {TopoJSONTopology} topology TopoJSON object.
* @param {ol.parser.ReadFeaturesOptions=} opt_options Reader options.
* @return {Array.<ol.Feature>} Parsed features.
* @private
*/
ol.parser.TopoJSON.prototype.readFeaturesFromTopology_ = function(
topology, opt_options) {
var transform = topology.transform;
var scale = transform.scale;
var translate = transform.translate;
var arcs = topology.arcs;
this.transformArcs_(arcs, scale, translate);
var objects = topology.objects;
var features = [];
for (var key in objects) {
if (objects[key].type === 'GeometryCollection') {
features.push.apply(features, this.readFeaturesFromGeometryCollection_(
/** @type {TopoJSONGeometryCollection} */ (objects[key]),
arcs, scale, translate, opt_options));
} else {
features.push(this.readFeatureFromGeometry_(
/** @type {TopoJSONGeometry} */ (objects[key]),
arcs, scale, translate, opt_options));
}
}
return features;
};
/**
* Create a linestring from a TopoJSON geometry object.
*
* @param {TopoJSONLineString} object TopoJSON object.
* @param {Array.<ol.geom.VertexArray>} arcs Array of arcs.
* @param {ol.parser.ReadFeaturesOptions=} opt_options Reader options.
* @return {ol.geom.LineString} Geometry.
* @private
*/
ol.parser.TopoJSON.prototype.readLineString_ = function(object, arcs,
opt_options) {
var coordinates = this.concatenateArcs_(object.arcs, arcs);
// TODO: make feature optional in callback
var callback = opt_options && opt_options.callback;
var sharedVertices;
if (callback) {
sharedVertices = callback(this.feature_, ol.geom.GeometryType.LINESTRING);
}
return new ol.geom.LineString(coordinates, sharedVertices);
};
/**
* Create a multi-linestring from a TopoJSON geometry object.
*
* @param {TopoJSONMultiLineString} object TopoJSON object.
* @param {Array.<ol.geom.VertexArray>} arcs Array of arcs.
* @param {ol.parser.ReadFeaturesOptions=} opt_options Reader options.
* @return {ol.geom.MultiLineString} Geometry.
* @private
*/
ol.parser.TopoJSON.prototype.readMultiLineString_ = function(object, arcs,
opt_options) {
var array = object.arcs; // I'm out of good names
var num = array.length;
var coordinates = new Array(num);
for (var i = 0; i < num; ++i) {
coordinates[i] = this.concatenateArcs_(array[i], arcs);
}
// TODO: make feature optional in callback
var callback = opt_options && opt_options.callback;
var sharedVertices;
if (callback) {
sharedVertices = callback(this.feature_,
ol.geom.GeometryType.MULTILINESTRING);
}
return new ol.geom.MultiLineString(coordinates, sharedVertices);
};
/**
* Create a multi-point from a TopoJSON geometry object.
*
* @param {TopoJSONMultiPoint} object TopoJSON object.
* @param {Array.<number>} scale Scale for each dimension.
* @param {Array.<number>} translate Translation for each dimension.
* @param {ol.parser.ReadFeaturesOptions=} opt_options Reader options.
* @return {ol.geom.MultiPoint} Geometry.
* @private
*/
ol.parser.TopoJSON.prototype.readMultiPoint_ = function(object, scale,
translate, opt_options) {
var coordinates = object.coordinates;
for (var i = 0, ii = coordinates.length; i < ii; ++i) {
this.transformVertex_(coordinates[i], scale, translate);
}
// TODO: make feature optional in callback
var callback = opt_options && opt_options.callback;
var sharedVertices;
if (callback) {
sharedVertices = callback(this.feature_, ol.geom.GeometryType.MULTIPOINT);
}
return new ol.geom.MultiPoint(coordinates, sharedVertices);
};
/**
* Create a multi-polygon from a TopoJSON geometry object.
*
* @param {TopoJSONMultiPolygon} object TopoJSON object.
* @param {Array.<ol.geom.VertexArray>} arcs Array of arcs.
* @param {ol.parser.ReadFeaturesOptions=} opt_options Reader options.
* @return {ol.geom.MultiPolygon} Geometry.
* @private
*/
ol.parser.TopoJSON.prototype.readMultiPolygon_ = function(object, arcs,
opt_options) {
var array = object.arcs;
var numPolys = array.length;
var coordinates = new Array(numPolys);
var polyArray, numRings, ringCoords, j;
for (var i = 0; i < numPolys; ++i) {
// for each polygon
polyArray = array[i];
numRings = polyArray.length;
ringCoords = new Array(numRings);
for (j = 0; j < numRings; ++j) {
// for each ring
ringCoords[j] = this.concatenateArcs_(polyArray[j], arcs);
}
coordinates[i] = ringCoords;
}
// TODO: make feature optional in callback
var callback = opt_options && opt_options.callback;
var sharedVertices;
if (callback) {
sharedVertices = callback(this.feature_, ol.geom.GeometryType.MULTIPOLYGON);
}
return new ol.geom.MultiPolygon(coordinates, sharedVertices);
};
/**
* Create a point from a TopoJSON geometry object.
*
* @param {TopoJSONPoint} object TopoJSON object.
* @param {Array.<number>} scale Scale for each dimension.
* @param {Array.<number>} translate Translation for each dimension.
* @param {ol.parser.ReadFeaturesOptions=} opt_options Reader options.
* @return {ol.geom.Point} Geometry.
* @private
*/
ol.parser.TopoJSON.prototype.readPoint_ = function(object, scale, translate,
opt_options) {
var coordinates = object.coordinates;
this.transformVertex_(coordinates, scale, translate);
// TODO: make feature optional in callback
var callback = opt_options && opt_options.callback;
var sharedVertices;
if (callback) {
sharedVertices = callback(this.feature_, ol.geom.GeometryType.POINT);
}
return new ol.geom.Point(coordinates, sharedVertices);
};
/**
* Create a polygon from a TopoJSON geometry object.
*
* @param {TopoJSONPolygon} object TopoJSON object.
* @param {Array.<ol.geom.VertexArray>} arcs Array of arcs.
* @param {ol.parser.ReadFeaturesOptions=} opt_options Reader options.
* @return {ol.geom.Polygon} Geometry.
* @private
*/
ol.parser.TopoJSON.prototype.readPolygon_ = function(object, arcs,
opt_options) {
var array = object.arcs; // I'm out of good names
var num = array.length;
var coordinates = new Array(num);
for (var i = 0; i < num; ++i) {
coordinates[i] = this.concatenateArcs_(array[i], arcs);
}
// TODO: make feature optional in callback
var callback = opt_options && opt_options.callback;
var sharedVertices;
if (callback) {
sharedVertices = callback(this.feature_, ol.geom.GeometryType.POLYGON);
}
return new ol.geom.Polygon(coordinates, sharedVertices);
};
/**
* Apply a linear transform to array of arcs. The provided array of arcs is
* modified in place.
*
* @param {Array.<ol.geom.VertexArray>} arcs Array of arcs.
* @param {Array.<number>} scale Scale for each dimension.
* @param {Array.<number>} translate Translation for each dimension.
* @private
*/
ol.parser.TopoJSON.prototype.transformArcs_ = function(arcs, scale, translate) {
for (var i = 0, ii = arcs.length; i < ii; ++i) {
this.transformArc_(arcs[i], scale, translate);
}
};
/**
* Apply a linear transform to an arc. The provided arc is modified in place.
*
* @param {ol.geom.VertexArray} arc Arc.
* @param {Array.<number>} scale Scale for each dimension.
* @param {Array.<number>} translate Translation for each dimension.
* @private
*/
ol.parser.TopoJSON.prototype.transformArc_ = function(arc, scale, translate) {
var x = 0;
var y = 0;
var vertex;
for (var i = 0, ii = arc.length; i < ii; ++i) {
vertex = arc[i];
x += vertex[0];
y += vertex[1];
vertex[0] = x;
vertex[1] = y;
this.transformVertex_(vertex, scale, translate);
}
};
/**
* Apply a linear transform to a vertex. The provided vertex is modified in
* place.
*
* @param {ol.geom.Vertex} vertex Vertex.
* @param {Array.<number>} scale Scale for each dimension.
* @param {Array.<number>} translate Translation for each dimension.
* @private
*/
ol.parser.TopoJSON.prototype.transformVertex_ = function(vertex, scale,
translate) {
vertex[0] = vertex[0] * scale[0] + translate[0];
vertex[1] = vertex[1] * scale[1] + translate[1];
};
/**
* Parse a TopoJSON string.
* @param {string} str TopoJSON string.
* @return {Array.<ol.Feature>} Array of features.
*/
ol.parser.TopoJSON.read = function(str) {
return ol.parser.TopoJSON.getInstance().read(str);
};

View File

@@ -44,7 +44,9 @@ ol.proj.EPSG4326.PROJECTIONS = [
new ol.proj.EPSG4326('EPSG:4326', 'neu'),
new ol.proj.EPSG4326('urn:ogc:def:crs:EPSG:6.6:4326', 'neu'),
new ol.proj.EPSG4326('urn:ogc:def:crs:OGC:1.3:CRS84'),
new ol.proj.EPSG4326('urn:ogc:def:crs:OGC:2:84')
new ol.proj.EPSG4326('urn:ogc:def:crs:OGC:2:84'),
new ol.proj.EPSG4326('http://www.opengis.net/gml/srs/epsg.xml#4326', 'neu'),
new ol.proj.EPSG4326('urn:x-ogc:def:crs:EPSG:4326', 'neu')
];

View File

@@ -94,7 +94,7 @@ ol.renderer.canvas.Map.prototype.renderFrame = function(frameState) {
if (goog.isNull(frameState)) {
if (this.renderedVisible_) {
goog.style.showElement(this.canvas_, false);
goog.style.setElementShown(this.canvas_, false);
this.renderedVisible_ = false;
}
return;
@@ -156,7 +156,7 @@ ol.renderer.canvas.Map.prototype.renderFrame = function(frameState) {
}
if (!this.renderedVisible_) {
goog.style.showElement(this.canvas_, true);
goog.style.setElementShown(this.canvas_, true);
this.renderedVisible_ = true;
}

View File

@@ -86,8 +86,7 @@ ol.renderer.canvas.VectorLayer = function(mapRenderer, layer) {
*/
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,
goog.events.listen(layer, goog.events.EventType.CHANGE,
this.handleLayerChange_, false, this);
/**
@@ -177,10 +176,13 @@ goog.inherits(ol.renderer.canvas.VectorLayer, ol.renderer.canvas.Layer);
* @private
*/
ol.renderer.canvas.VectorLayer.prototype.expireTiles_ = function(opt_extent) {
var tileCache = this.tileCache_;
if (goog.isDef(opt_extent)) {
// TODO: implement this
var tileRange = this.tileGrid_.getTileRangeForExtentAndZ(opt_extent, 0);
tileCache.pruneTileRange(tileRange);
} else {
tileCache.clear();
}
this.tileCache_.clear();
};
@@ -228,9 +230,11 @@ ol.renderer.canvas.VectorLayer.prototype.getFeatureInfoForPixel =
* @param {function(Array.<ol.Feature>, ol.layer.Layer)} success Callback for
* successful queries. The passed arguments are the resulting features
* and the layer.
* @param {function()=} opt_error Callback for unsuccessful queries.
*/
ol.renderer.canvas.VectorLayer.prototype.getFeaturesForPixel =
function(pixel, success) {
function(pixel, success, opt_error) {
// TODO What do we want to pass to the error callback?
var map = this.getMap();
var result = [];
@@ -247,7 +251,15 @@ ol.renderer.canvas.VectorLayer.prototype.getFeaturesForPixel =
var locationMin = [location[0] - halfMaxWidth, location[1] - halfMaxHeight];
var locationMax = [location[0] + halfMaxWidth, location[1] + halfMaxHeight];
var locationBbox = ol.extent.boundingExtent([locationMin, locationMax]);
var candidates = layer.getFeaturesObjectForExtent(locationBbox);
var candidates = layer.getFeaturesObjectForExtent(locationBbox,
map.getView().getView2D().getProjection());
if (goog.isNull(candidates)) {
// data is not loaded
if (goog.isDef(opt_error)) {
goog.global.setTimeout(function() { opt_error(); }, 0);
}
return;
}
var candidate, geom, type, symbolBounds, symbolSize, halfWidth, halfHeight,
coordinates, j;
@@ -295,12 +307,11 @@ ol.renderer.canvas.VectorLayer.prototype.getFeaturesForPixel =
/**
* @param {goog.events.Event} event Layer change event.
* @param {ol.layer.VectorLayerEventObject} 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.expireTiles_(event.extent);
this.requestMapRenderFrame_();
};
@@ -446,6 +457,7 @@ ol.renderer.canvas.VectorLayer.prototype.renderFrame =
dirty = false,
i, type, tileExtent,
groups, group, j, numGroups, featuresObject, tileHasFeatures;
fetchTileData:
for (x = tileRange.minX; x <= tileRange.maxX; ++x) {
for (y = tileRange.minY; y <= tileRange.maxY; ++y) {
tileCoord = new ol.TileCoord(0, x, y);
@@ -464,7 +476,12 @@ ol.renderer.canvas.VectorLayer.prototype.renderFrame =
if (!goog.isDef(featuresToRender[type])) {
featuresToRender[type] = {};
}
featuresObject = layer.getFeaturesObjectForExtent(tileExtent, type);
featuresObject = layer.getFeaturesObjectForExtent(tileExtent,
projection, type, this.requestMapRenderFrame_);
if (goog.isNull(featuresObject)) {
deferred = true;
break fetchTileData;
}
tileHasFeatures = tileHasFeatures ||
!goog.object.isEmpty(featuresObject);
goog.object.extend(featuresToRender[type], featuresObject);
@@ -510,6 +527,7 @@ ol.renderer.canvas.VectorLayer.prototype.renderFrame =
tile.getContext('2d').drawImage(sketchCanvas,
(tileRange.minX - tileCoord.x) * tileSize[0],
(tileCoord.y - tileRange.maxY) * tileSize[1]);
// TODO: Create an ol.VectorTile subclass of ol.Tile
this.tileCache_.set(key, [tile, symbolSizes, maxSymbolSize]);
}
finalContext.drawImage(tile,

View File

@@ -8,7 +8,6 @@ goog.require('goog.events');
goog.require('goog.events.EventType');
goog.require('goog.vec.Mat4');
goog.require('ol.Feature');
goog.require('ol.extent');
goog.require('ol.geom.AbstractCollection');
goog.require('ol.geom.Geometry');
goog.require('ol.geom.GeometryType');
@@ -154,7 +153,7 @@ ol.renderer.canvas.VectorRenderer.prototype.renderLineStringFeatures_ =
i, ii, feature, id, currentSize, geometry, components, j, jj, line, dim,
k, kk, vec, strokeSize;
context.globalAlpha = symbolizer.opacity;
context.globalAlpha = symbolizer.strokeOpacity;
context.strokeStyle = symbolizer.strokeColor;
context.lineWidth = symbolizer.strokeWidth;
context.lineCap = 'round'; // TODO: accept this as a symbolizer property
@@ -307,11 +306,13 @@ ol.renderer.canvas.VectorRenderer.prototype.renderPolygonFeatures_ =
var context = this.context_,
strokeColor = symbolizer.strokeColor,
strokeWidth = symbolizer.strokeWidth,
strokeOpacity = symbolizer.strokeOpacity,
fillColor = symbolizer.fillColor,
fillOpacity = symbolizer.fillOpacity,
globalAlpha,
i, ii, geometry, components, j, jj, poly,
rings, numRings, ring, dim, k, kk, vec;
context.globalAlpha = symbolizer.opacity;
if (strokeColor) {
context.strokeStyle = strokeColor;
if (strokeWidth) {
@@ -360,7 +361,17 @@ ol.renderer.canvas.VectorRenderer.prototype.renderPolygonFeatures_ =
}
if (fillColor && strokeColor) {
// scenario 3 - fill and stroke each time
if (fillOpacity !== globalAlpha) {
goog.asserts.assertNumber(fillOpacity);
context.globalAlpha = fillOpacity;
globalAlpha = fillOpacity;
}
context.fill();
if (strokeOpacity !== globalAlpha) {
goog.asserts.assertNumber(strokeOpacity);
context.globalAlpha = strokeOpacity;
globalAlpha = strokeOpacity;
}
context.stroke();
if (i < ii - 1 || j < jj - 1) {
context.beginPath();
@@ -372,9 +383,19 @@ ol.renderer.canvas.VectorRenderer.prototype.renderPolygonFeatures_ =
if (!(fillColor && strokeColor)) {
if (fillColor) {
// scenario 2 - fill all at once
if (fillOpacity !== globalAlpha) {
goog.asserts.assertNumber(fillOpacity);
context.globalAlpha = fillOpacity;
globalAlpha = fillOpacity;
}
context.fill();
} else {
// scenario 1 - stroke all at once
if (strokeOpacity !== globalAlpha) {
goog.asserts.assertNumber(strokeOpacity);
context.globalAlpha = strokeOpacity;
globalAlpha = strokeOpacity;
}
context.stroke();
}
}
@@ -401,8 +422,6 @@ ol.renderer.canvas.VectorRenderer.renderCircle_ = function(circle) {
canvas.height = size;
canvas.width = size;
context.globalAlpha = circle.opacity;
if (fillColor) {
context.fillStyle = fillColor;
}
@@ -417,9 +436,13 @@ ol.renderer.canvas.VectorRenderer.renderCircle_ = function(circle) {
context.arc(mid, mid, circle.size / 2, 0, twoPi, true);
if (fillColor) {
goog.asserts.assertNumber(circle.fillOpacity);
context.globalAlpha = circle.fillOpacity;
context.fill();
}
if (strokeColor) {
goog.asserts.assertNumber(circle.strokeOpacity);
context.globalAlpha = circle.strokeOpacity;
context.stroke();
}
return canvas;
@@ -446,8 +469,7 @@ ol.renderer.canvas.VectorRenderer.getLabelVectors = function(geometry) {
return [[geometry.get(0), geometry.get(1), 0]];
}
if (type == ol.geom.GeometryType.POLYGON) {
// TODO: better label placement
var coordinates = ol.extent.getCenter(geometry.getBounds());
var coordinates = geometry.getInteriorPoint();
return [[coordinates[0], coordinates[1], 0]];
}
throw new Error('Label rendering not implemented for geometry type: ' +

View File

@@ -71,7 +71,7 @@ ol.renderer.dom.Map.prototype.renderFrame = function(frameState) {
if (goog.isNull(frameState)) {
if (this.renderedVisible_) {
goog.style.showElement(this.layersPane_, false);
goog.style.setElementShown(this.layersPane_, false);
this.renderedVisible_ = false;
}
return;
@@ -98,7 +98,7 @@ ol.renderer.dom.Map.prototype.renderFrame = function(frameState) {
}
if (!this.renderedVisible_) {
goog.style.showElement(this.layersPane_, true);
goog.style.setElementShown(this.layersPane_, true);
this.renderedVisible_ = true;
}

View File

@@ -76,7 +76,7 @@ ol.renderer.dom.TileLayer.prototype.renderFrame =
if (!layerState.visible) {
if (this.renderedVisible_) {
goog.style.showElement(this.target, false);
goog.style.setElementShown(this.target, false);
this.renderedVisible_ = false;
}
return;
@@ -226,7 +226,7 @@ ol.renderer.dom.TileLayer.prototype.renderFrame =
}
if (layerState.visible && !this.renderedVisible_) {
goog.style.showElement(this.target, true);
goog.style.setElementShown(this.target, true);
this.renderedVisible_ = true;
}

View File

@@ -73,6 +73,26 @@ ol.renderer.Layer = function(mapRenderer, layer) {
goog.inherits(ol.renderer.Layer, goog.Disposable);
/**
* @param {ol.Pixel} pixel Pixel coordinate relative to the map viewport.
* @param {function(string, ol.layer.Layer)} success Callback for
* successful queries. The passed arguments are the resulting feature
* information and the layer.
* @param {function()=} opt_error Callback for unsuccessful queries.
*/
ol.renderer.Layer.prototype.getFeatureInfoForPixel =
function(pixel, success, opt_error) {
var layer = this.getLayer();
var source = layer.getSource();
if (goog.isFunction(source.getFeatureInfoForPixel)) {
var callback = function(layerFeatureInfo) {
success(layerFeatureInfo, layer);
};
source.getFeatureInfoForPixel(pixel, this.getMap(), callback, opt_error);
}
};
/**
* @protected
* @return {ol.layer.Layer} Layer.

View File

@@ -101,12 +101,12 @@ ol.renderer.Map.prototype.getCanvas = goog.functions.NULL;
/**
* @param {ol.Pixel} pixel Pixel coordinate relative to the map viewport.
* @param {Array.<ol.layer.Layer>} layers Layers to query.
* @param {function(Array.<ol.Feature|string>)} success Callback for
* @param {function(Array.<Array.<string|undefined>>)} success Callback for
* successful queries. The passed argument is the resulting feature
* information. Layers that are able to provide attribute data will put
* ol.Feature instances, other layers will put a string which can either
* be plain text or markup.
* @param {function(Object)=} opt_error Callback for unsuccessful
* @param {function()=} opt_error Callback for unsuccessful
* queries.
*/
ol.renderer.Map.prototype.getFeatureInfoForPixel =
@@ -137,12 +137,12 @@ ol.renderer.Map.prototype.getFeatureInfoForPixel =
/**
* @param {ol.Pixel} pixel Pixel coordinate relative to the map viewport.
* @param {Array.<ol.layer.Layer>} layers Layers to query.
* @param {function(Array.<ol.Feature|string>)} success Callback for
* @param {function(Array.<Array.<ol.Feature|undefined>>)} success Callback for
* successful queries. The passed argument is the resulting feature
* information. Layers that are able to provide attribute data will put
* ol.Feature instances, other layers will put a string which can either
* be plain text or markup.
* @param {function(Object)=} opt_error Callback for unsuccessful
* @param {function()=} opt_error Callback for unsuccessful
* queries.
*/
ol.renderer.Map.prototype.getFeaturesForPixel =

View File

@@ -4,11 +4,12 @@ goog.provide('ol.renderer.webgl.Map');
goog.require('goog.array');
goog.require('goog.asserts');
goog.require('goog.debug.Logger');
goog.require('goog.dom');
goog.require('goog.dom.TagName');
goog.require('goog.events');
goog.require('goog.events.Event');
goog.require('goog.log');
goog.require('goog.log.Logger');
goog.require('goog.object');
goog.require('goog.style');
goog.require('goog.webgl');
@@ -417,7 +418,7 @@ ol.renderer.webgl.Map.prototype.getProgram = function(
if (goog.DEBUG) {
if (!gl.getProgramParameter(program, goog.webgl.LINK_STATUS) &&
!gl.isContextLost()) {
this.logger_.severe(gl.getProgramInfoLog(program));
goog.log.error(this.logger_, gl.getProgramInfoLog(program));
}
}
goog.asserts.assert(
@@ -445,7 +446,7 @@ ol.renderer.webgl.Map.prototype.getShader = function(shaderObject) {
if (goog.DEBUG) {
if (!gl.getShaderParameter(shader, goog.webgl.COMPILE_STATUS) &&
!gl.isContextLost()) {
this.logger_.severe(gl.getShaderInfoLog(shader));
goog.log.error(this.logger_, gl.getShaderInfoLog(shader));
}
}
goog.asserts.assert(
@@ -519,10 +520,10 @@ ol.renderer.webgl.Map.prototype.isTileTextureLoaded = function(tile) {
/**
* @private
* @type {goog.debug.Logger}
* @type {goog.log.Logger}
*/
ol.renderer.webgl.Map.prototype.logger_ =
goog.debug.Logger.getLogger('ol.renderer.webgl.Map');
goog.log.getLogger('ol.renderer.webgl.Map');
/**
@@ -538,7 +539,7 @@ ol.renderer.webgl.Map.prototype.renderFrame = function(frameState) {
if (goog.isNull(frameState)) {
if (this.renderedVisible_) {
goog.style.showElement(this.canvas_, false);
goog.style.setElementShown(this.canvas_, false);
this.renderedVisible_ = false;
}
return false;
@@ -651,7 +652,7 @@ ol.renderer.webgl.Map.prototype.renderFrame = function(frameState) {
}
if (!this.renderedVisible_) {
goog.style.showElement(this.canvas_, true);
goog.style.setElementShown(this.canvas_, true);
this.renderedVisible_ = true;
}

View File

@@ -11,33 +11,6 @@ goog.require('ol.array');
ol.ResolutionConstraintType;
/**
* @param {number} power Power.
* @param {number} maxResolution Maximum resolution.
* @param {number=} opt_minResolution Minimum resolution.
* @return {ol.ResolutionConstraintType} Zoom function.
*/
ol.ResolutionConstraint.createContinuous =
function(power, maxResolution, opt_minResolution) {
var minResolution = opt_minResolution || 0;
return (
/**
* @param {number|undefined} resolution Resolution.
* @param {number} delta Delta.
* @param {number} direction Direction.
* @return {number|undefined} Resolution.
*/
function(resolution, delta, direction) {
if (goog.isDef(resolution)) {
resolution /= Math.pow(power, delta);
return goog.math.clamp(resolution, minResolution, maxResolution);
} else {
return undefined;
}
});
};
/**
* @param {Array.<number>} resolutions Resolutions.
* @return {ol.ResolutionConstraintType} Zoom function.

View File

@@ -0,0 +1,18 @@
goog.provide('ol.source.FeatureInfoSource');
/**
* @interface
*/
ol.source.FeatureInfoSource = function() {};
/**
* @param {ol.Pixel} pixel Pixel.
* @param {ol.Map} map The map that the pixel belongs to.
* @param {function(string)} success Callback with feature info.
* @param {function()=} opt_error Optional error callback.
*/
ol.source.FeatureInfoSource.prototype.getFeatureInfoForPixel =
goog.abstractMethod;

View File

@@ -1,8 +1,10 @@
goog.provide('ol.source.SingleImageWMS');
goog.require('goog.asserts');
goog.require('ol.Image');
goog.require('ol.ImageUrlFunction');
goog.require('ol.extent');
goog.require('ol.source.FeatureInfoSource');
goog.require('ol.source.ImageSource');
goog.require('ol.source.wms');
@@ -11,6 +13,7 @@ goog.require('ol.source.wms');
/**
* @constructor
* @extends {ol.source.ImageSource}
* @implements {ol.source.FeatureInfoSource}
* @param {ol.source.SingleImageWMSOptions} options Options.
*/
ol.source.SingleImageWMS = function(options) {
@@ -28,6 +31,13 @@ ol.source.SingleImageWMS = function(options) {
imageUrlFunction: imageUrlFunction
});
/**
* @private
* @type {ol.source.WMSGetFeatureInfoOptions}
*/
this.getFeatureInfoOptions_ = goog.isDef(options.getFeatureInfoOptions) ?
options.getFeatureInfoOptions : {};
/**
* @private
* @type {ol.Image}
@@ -68,3 +78,22 @@ ol.source.SingleImageWMS.prototype.getImage =
this.image_ = this.createImage(extent, resolution, size, projection);
return this.image_;
};
/**
* @inheritDoc
*/
ol.source.SingleImageWMS.prototype.getFeatureInfoForPixel =
function(pixel, map, success, opt_error) {
var view2D = map.getView().getView2D(),
projection = view2D.getProjection(),
size = map.getSize(),
bottomLeft = map.getCoordinateFromPixel([0, size[1]]),
topRight = map.getCoordinateFromPixel([size[0], 0]),
extent = [bottomLeft[0], topRight[0], bottomLeft[1], topRight[1]],
url = this.imageUrlFunction(extent, size, projection);
goog.asserts.assert(goog.isDef(url),
'ol.source.SingleImageWMS#imageUrlFunction does not return a url');
ol.source.wms.getFeatureInfo(url, pixel, this.getFeatureInfoOptions_, success,
opt_error);
};

View File

@@ -76,17 +76,6 @@ ol.source.StamenProviderConfig = {
};
/**
* @const {Array.<ol.Attribution>}
*/
ol.source.STAMEN_ATTRIBUTIONS = [
new ol.Attribution(
'Map tiles by <a href="http://stamen.com/">Stamen Design</a>, under ' +
'<a href="http://creativecommons.org/licenses/by/3.0/">CC BY 3.0</a>.'),
ol.source.OSM.DATA_ATTRIBUTION
];
/**
* @constructor
@@ -108,7 +97,7 @@ ol.source.Stamen = function(options) {
layerConfig.extension;
goog.base(this, {
attributions: ol.source.STAMEN_ATTRIBUTIONS,
attributions: ol.source.Stamen.ATTRIBUTIONS,
crossOrigin: 'anonymous',
maxZoom: providerConfig.maxZoom,
// FIXME uncomment the following when tilegrid supports minZoom
@@ -119,3 +108,14 @@ ol.source.Stamen = function(options) {
};
goog.inherits(ol.source.Stamen, ol.source.XYZ);
/**
* @const {Array.<ol.Attribution>}
*/
ol.source.Stamen.ATTRIBUTIONS = [
new ol.Attribution(
'Map tiles by <a href="http://stamen.com/">Stamen Design</a>, under ' +
'<a href="http://creativecommons.org/licenses/by/3.0/">CC BY 3.0</a>.'),
ol.source.OSM.DATA_ATTRIBUTION
];

View File

@@ -3,10 +3,12 @@
goog.provide('ol.source.TiledWMS');
goog.require('goog.array');
goog.require('goog.asserts');
goog.require('goog.math');
goog.require('ol.TileCoord');
goog.require('ol.TileUrlFunction');
goog.require('ol.extent');
goog.require('ol.source.FeatureInfoSource');
goog.require('ol.source.ImageTileSource');
goog.require('ol.source.wms');
@@ -15,9 +17,11 @@ goog.require('ol.source.wms');
/**
* @constructor
* @extends {ol.source.ImageTileSource}
* @implements {ol.source.FeatureInfoSource}
* @param {ol.source.TiledWMSOptions} options Tiled WMS options.
*/
ol.source.TiledWMS = function(options) {
var tileGrid;
if (goog.isDef(options.tileGrid)) {
tileGrid = options.tileGrid;
@@ -28,6 +32,7 @@ ol.source.TiledWMS = function(options) {
if (!goog.isDef(urls) && goog.isDef(options.url)) {
urls = ol.TileUrlFunction.expandUrl(options.url);
}
if (goog.isDef(urls)) {
var tileUrlFunctions = goog.array.map(
urls, function(url) {
@@ -81,5 +86,35 @@ ol.source.TiledWMS = function(options) {
tileCoordTransform, tileUrlFunction)
});
/**
* @private
* @type {ol.source.WMSGetFeatureInfoOptions}
*/
this.getFeatureInfoOptions_ = goog.isDef(options.getFeatureInfoOptions) ?
options.getFeatureInfoOptions : {};
};
goog.inherits(ol.source.TiledWMS, ol.source.ImageTileSource);
/**
* @inheritDoc
*/
ol.source.TiledWMS.prototype.getFeatureInfoForPixel =
function(pixel, map, success, opt_error) {
var coord = map.getCoordinateFromPixel(pixel),
view2D = map.getView().getView2D(),
projection = view2D.getProjection(),
tileGrid = goog.isNull(this.tileGrid) ?
ol.tilegrid.getForProjection(projection) : this.tileGrid,
tileCoord = tileGrid.getTileCoordForCoordAndResolution(coord,
view2D.getResolution()),
tileExtent = tileGrid.getTileCoordExtent(tileCoord),
offset = map.getPixelFromCoordinate(ol.extent.getTopLeft(tileExtent)),
url = this.tileUrlFunction(tileCoord, projection);
goog.asserts.assert(goog.isDef(url),
'ol.source.TiledWMS#tileUrlFunction does not return a url');
ol.source.wms.getFeatureInfo(url,
[pixel[0] - offset[0], pixel[1] - offset[1]], this.getFeatureInfoOptions_,
success, opt_error);
};

View File

@@ -0,0 +1,2 @@
@exportSymbol ol.source.TileSource
@exportProperty ol.source.TileSource.prototype.getTileGrid

View File

@@ -1 +1 @@
@exportClass ol.source.Vector ol.source.SourceOptions
@exportClass ol.source.Vector ol.source.VectorOptions

View File

@@ -1,15 +1,95 @@
goog.provide('ol.source.Vector');
goog.require('goog.asserts');
goog.require('goog.net.XhrIo');
goog.require('ol.source.Source');
/**
* @enum {number}
*/
ol.source.VectorLoadState = {
IDLE: 0,
LOADING: 1,
LOADED: 2,
ERROR: 3
};
/**
* @constructor
* @extends {ol.source.Source}
* @param {ol.source.SourceOptions} options Source options.
* @param {ol.source.VectorOptions} options Vector source options.
*/
ol.source.Vector = function(options) {
goog.base(this, options);
/**
* @private
* @type {Object|string}
*/
this.data_ = goog.isDef(options.data) ? options.data : null;
/**
* @private
* @type {ol.source.VectorLoadState}
*/
this.loadState_ = ol.source.VectorLoadState.IDLE;
/**
* @private
* @type {ol.parser.Parser}
*/
this.parser_ = goog.isDef(options.parser) ? options.parser : null;
/**
* @private
* @type {string|undefined}
*/
this.url_ = options.url;
goog.base(this, {
attributions: options.attributions,
extent: options.extent,
logo: options.logo,
projection: options.projection
});
};
goog.inherits(ol.source.Vector, ol.source.Source);
/**
* @param {ol.layer.Vector} layer Layer that parses the data.
* @param {ol.Extent} extent Extent that needs to be fetched.
* @param {ol.Projection} projection Projection of the view.
* @param {function()=} opt_callback Callback which is called when features are
* parsed after loading.
* @return {ol.source.VectorLoadState} The current load state.
*/
ol.source.Vector.prototype.prepareFeatures = function(layer, extent, projection,
opt_callback) {
// TODO: Implement strategies. BBOX aware strategies will need the extent.
if (goog.isDef(this.url_) &&
this.loadState_ == ol.source.VectorLoadState.IDLE) {
this.loadState_ = ol.source.VectorLoadState.LOADING;
goog.net.XhrIo.send(this.url_, goog.bind(function(event) {
var xhr = event.target;
if (xhr.isSuccess()) {
// TODO: Get source projection from data if supported by parser.
layer.parseFeatures(xhr.getResponseText(), this.parser_, projection);
this.loadState_ = ol.source.VectorLoadState.LOADED;
if (goog.isDef(opt_callback)) {
opt_callback();
}
} else {
// TODO: Error handling.
this.loadState_ = ol.source.VectorLoadState.ERROR;
}
}, this));
} else if (!goog.isNull(this.data_)) {
layer.parseFeatures(this.data_, this.parser_, projection);
this.data_ = null;
this.loadState_ = ol.source.VectorLoadState.LOADED;
}
return this.loadState_;
};

View File

@@ -0,0 +1 @@
@exportSymbol ol.source.WMSGetFeatureInfoMethod

View File

@@ -1,9 +1,29 @@
goog.provide('ol.source.WMSGetFeatureInfoMethod');
goog.provide('ol.source.wms');
goog.require('goog.net.XhrIo');
goog.require('goog.object');
goog.require('goog.uri.utils');
/**
* Method to use to get WMS feature info.
* @enum {string}
*/
ol.source.WMSGetFeatureInfoMethod = {
/**
* Load the info in an IFRAME. Only works with 'text/html and 'text/plain' as
* `INFO_FORMAT`.
*/
IFRAME: 'iframe',
/**
* Use an asynchronous GET request. Requires CORS headers or a server at the
* same origin as the application script.
*/
XHR_GET: 'xhr_get'
};
/**
* @param {string} baseUrl WMS base url.
* @param {Object.<string, string|number>} params Request parameters.
@@ -40,3 +60,60 @@ ol.source.wms.getUrl =
return goog.uri.utils.appendParamsFromMap(baseUrl, baseParams);
};
/**
* @param {string} url URL as provided by the url function.
* @param {ol.Pixel} pixel Pixel.
* @param {Object} options Options as defined in the source.
* @param {function(string)} success Callback function for successful queries.
* @param {function()=} opt_error Optional callback function for unsuccessful
* queries.
*/
ol.source.wms.getFeatureInfo =
function(url, pixel, options, success, opt_error) {
// TODO: This could be done in a smarter way if the url function was not a
// closure
url = url.replace('REQUEST=GetMap', 'REQUEST=GetFeatureInfo')
.replace(ol.source.wms.regExes.layers, 'LAYERS=$1&QUERY_LAYERS=$1');
options = goog.isDef(options) ? goog.object.clone(options) : {};
var localOptions = {
method: ol.source.WMSGetFeatureInfoMethod.IFRAME,
params: {}
};
goog.object.extend(localOptions, options);
var params = {'INFO_FORMAT': 'text/html'},
version = parseFloat(url.match(ol.source.wms.regExes.version)[1]),
x = Math.round(pixel[0]),
y = Math.round(pixel[1]);
if (version >= 1.3) {
goog.object.extend(params, {'I': x, 'J': y});
} else {
goog.object.extend(params, {'X': x, 'Y': y});
}
goog.object.extend(params, localOptions.params);
url = goog.uri.utils.appendParamsFromMap(url, params);
if (localOptions.method == ol.source.WMSGetFeatureInfoMethod.IFRAME) {
goog.global.setTimeout(function() {
success('<iframe seamless src="' + url + '"></iframe>');
}, 0);
} else if (localOptions.method == ol.source.WMSGetFeatureInfoMethod.XHR_GET) {
goog.net.XhrIo.send(url, function(event) {
var xhr = event.target;
if (xhr.isSuccess()) {
success(xhr.getResponseText());
} else if (goog.isDef(opt_error)) {
opt_error();
}
});
}
};
/**
* @enum {RegExp}
*/
ol.source.wms.regExes = {
layers: (/LAYERS=([^&]+)/),
version: (/VERSION=([^&]+)/)
};

View File

@@ -233,7 +233,7 @@ ol.source.WMTS.optionsFromCapabilities = function(wmtsCap, layer) {
(l['resourceUrls']['tile'][format]);
break;
case 'KVP':
requestEncoding = ol.source.WMTSRequestEncoding.REST;
requestEncoding = ol.source.WMTSRequestEncoding.KVP;
urls = [];
goog.array.forEach(gets, function(elt, index, array) {
if (elt['constraints']['GetEncoding']['allowedValues'].hasOwnProperty(

View File

@@ -280,8 +280,7 @@ ol.structs.RTree.prototype.insertSubtree_ = function(node, root) {
*
* @param {Array.<ol.structs.RTreeNode>} nodes Array of nodes.
* @private
* @return {Array.<Array.<ol.structs.RTreeNode>>} An array of two new arrays
* of nodes.
* @return {Array.<ol.structs.RTreeNode>} An array of two nodes.
*/
ol.structs.RTree.prototype.linearSplit_ = function(nodes) {
var n = this.pickLinear_(nodes);
@@ -298,8 +297,7 @@ ol.structs.RTree.prototype.linearSplit_ = function(nodes) {
*
* @param {Array.<ol.structs.RTreeNode>} nodes Array of source nodes.
* @private
* @return {Array.<ol.structs.RTreeNode>} An array of two new arrays
* of nodes.
* @return {Array.<ol.structs.RTreeNode>} An array of two nodes.
*/
ol.structs.RTree.prototype.pickLinear_ = function(nodes) {
var lowestHighX = nodes.length - 1;

View File

@@ -51,7 +51,7 @@ goog.inherits(ol.style.IconLiteral, ol.style.PointLiteral);
* @inheritDoc
*/
ol.style.IconLiteral.prototype.equals = function(iconLiteral) {
return this.url == iconLiteral.type &&
return this.url == iconLiteral.url &&
this.width == iconLiteral.width &&
this.height == iconLiteral.height &&
this.opacity == iconLiteral.opacity &&
@@ -153,6 +153,101 @@ ol.style.Icon.prototype.createLiteral = function(opt_feature) {
};
/**
* Get the height.
* @return {ol.expr.Expression} Icon height.
*/
ol.style.Icon.prototype.getHeight = function() {
return this.height_;
};
/**
* Get the opacity.
* @return {ol.expr.Expression} Opacity.
*/
ol.style.Icon.prototype.getOpacity = function() {
return this.opacity_;
};
/**
* Get the rotation.
* @return {ol.expr.Expression} Icon rotation.
*/
ol.style.Icon.prototype.getRotation = function() {
return this.rotation_;
};
/**
* Get the url.
* @return {ol.expr.Expression} Icon url.
*/
ol.style.Icon.prototype.getUrl = function() {
return this.url_;
};
/**
* Get the width.
* @return {ol.expr.Expression} Icon width.
*/
ol.style.Icon.prototype.getWidth = function() {
return this.width_;
};
/**
* Set the height.
* @param {ol.expr.Expression} height Icon height.
*/
ol.style.Icon.prototype.setHeight = function(height) {
goog.asserts.assertInstanceof(height, ol.expr.Expression);
this.height_ = height;
};
/**
* Set the opacity.
* @param {ol.expr.Expression} opacity Opacity.
*/
ol.style.Icon.prototype.setOpacity = function(opacity) {
goog.asserts.assertInstanceof(opacity, ol.expr.Expression);
this.opacity_ = opacity;
};
/**
* Set the rotation.
* @param {ol.expr.Expression} rotation Icon rotation.
*/
ol.style.Icon.prototype.setRotation = function(rotation) {
goog.asserts.assertInstanceof(rotation, ol.expr.Expression);
this.rotation_ = rotation;
};
/**
* Set the url.
* @param {ol.expr.Expression} url Icon url.
*/
ol.style.Icon.prototype.setUrl = function(url) {
goog.asserts.assertInstanceof(url, ol.expr.Expression);
this.url_ = url;
};
/**
* Set the width.
* @param {ol.expr.Expression} width Icon width.
*/
ol.style.Icon.prototype.setWidth = function(width) {
goog.asserts.assertInstanceof(width, ol.expr.Expression);
this.width_ = width;
};
/**
* @type {ol.style.IconLiteral}
*/

View File

@@ -11,8 +11,8 @@ goog.require('ol.style.SymbolizerLiteral');
/**
* @typedef {{strokeColor: (string),
* strokeWidth: (number),
* opacity: (number)}}
* strokeOpacity: (number),
* strokeWidth: (number)}}
*/
ol.style.LineLiteralOptions;
@@ -31,15 +31,16 @@ ol.style.LineLiteral = function(options) {
/** @type {string} */
this.strokeColor = options.strokeColor;
goog.asserts.assertNumber(
options.strokeOpacity, 'strokeOpacity must be a number');
/** @type {number} */
this.strokeOpacity = options.strokeOpacity;
goog.asserts.assertNumber(
options.strokeWidth, 'strokeWidth must be a number');
/** @type {number} */
this.strokeWidth = options.strokeWidth;
goog.asserts.assertNumber(options.opacity, 'opacity must be a number');
/** @type {number} */
this.opacity = options.opacity;
};
goog.inherits(ol.style.LineLiteral, ol.style.SymbolizerLiteral);
@@ -49,8 +50,8 @@ goog.inherits(ol.style.LineLiteral, ol.style.SymbolizerLiteral);
*/
ol.style.LineLiteral.prototype.equals = function(lineLiteral) {
return this.strokeColor == lineLiteral.strokeColor &&
this.strokeWidth == lineLiteral.strokeWidth &&
this.opacity == lineLiteral.opacity;
this.strokeOpacity == lineLiteral.strokeOpacity &&
this.strokeWidth == lineLiteral.strokeWidth;
};
@@ -76,19 +77,19 @@ ol.style.Line = function(options) {
* @type {ol.expr.Expression}
* @private
*/
this.strokeWidth_ = !goog.isDef(options.strokeWidth) ?
new ol.expr.Literal(ol.style.LineDefaults.strokeWidth) :
(options.strokeWidth instanceof ol.expr.Expression) ?
options.strokeWidth : new ol.expr.Literal(options.strokeWidth);
this.strokeOpacity_ = !goog.isDef(options.strokeOpacity) ?
new ol.expr.Literal(ol.style.LineDefaults.strokeOpacity) :
(options.strokeOpacity instanceof ol.expr.Expression) ?
options.strokeOpacity : new ol.expr.Literal(options.strokeOpacity);
/**
* @type {ol.expr.Expression}
* @private
*/
this.opacity_ = !goog.isDef(options.opacity) ?
new ol.expr.Literal(ol.style.LineDefaults.opacity) :
(options.opacity instanceof ol.expr.Expression) ?
options.opacity : new ol.expr.Literal(options.opacity);
this.strokeWidth_ = !goog.isDef(options.strokeWidth) ?
new ol.expr.Literal(ol.style.LineDefaults.strokeWidth) :
(options.strokeWidth instanceof ol.expr.Expression) ?
options.strokeWidth : new ol.expr.Literal(options.strokeWidth);
};
goog.inherits(ol.style.Line, ol.style.Symbolizer);
@@ -104,26 +105,85 @@ ol.style.Line.prototype.createLiteral = function(opt_feature) {
this.strokeColor_, opt_feature);
goog.asserts.assertString(strokeColor, 'strokeColor must be a string');
var strokeOpacity = ol.expr.evaluateFeature(
this.strokeOpacity_, opt_feature);
goog.asserts.assertNumber(strokeOpacity, 'strokeOpacity must be a number');
var strokeWidth = ol.expr.evaluateFeature(
this.strokeWidth_, opt_feature);
goog.asserts.assertNumber(strokeWidth, 'strokeWidth must be a number');
var opacity = ol.expr.evaluateFeature(this.opacity_, opt_feature);
goog.asserts.assertNumber(opacity, 'opacity must be a number');
return new ol.style.LineLiteral({
strokeColor: strokeColor,
strokeWidth: strokeWidth,
opacity: opacity
strokeOpacity: strokeOpacity,
strokeWidth: strokeWidth
});
};
/**
* Get the stroke color.
* @return {ol.expr.Expression} Stroke color.
*/
ol.style.Line.prototype.getStrokeColor = function() {
return this.strokeColor_;
};
/**
* Get the stroke opacity.
* @return {ol.expr.Expression} Stroke opacity.
*/
ol.style.Line.prototype.getStrokeOpacity = function() {
return this.strokeOpacity_;
};
/**
* Get the stroke width.
* @return {ol.expr.Expression} Stroke width.
*/
ol.style.Line.prototype.getStrokeWidth = function() {
return this.strokeWidth_;
};
/**
* Set the stroke color.
* @param {ol.expr.Expression} strokeColor Stroke color.
*/
ol.style.Line.prototype.setStrokeColor = function(strokeColor) {
goog.asserts.assertInstanceof(strokeColor, ol.expr.Expression);
this.strokeColor_ = strokeColor;
};
/**
* Set the stroke opacity.
* @param {ol.expr.Expression} strokeOpacity Stroke opacity.
*/
ol.style.Line.prototype.setStrokeOpacity = function(strokeOpacity) {
goog.asserts.assertInstanceof(strokeOpacity, ol.expr.Expression);
this.strokeOpacity_ = strokeOpacity;
};
/**
* Set the stroke width.
* @param {ol.expr.Expression} strokeWidth Stroke width.
*/
ol.style.Line.prototype.setStrokeWidth = function(strokeWidth) {
goog.asserts.assertInstanceof(strokeWidth, ol.expr.Expression);
this.strokeWidth_ = strokeWidth;
};
/**
* @type {ol.style.LineLiteral}
*/
ol.style.LineDefaults = new ol.style.LineLiteral({
strokeColor: '#696969',
strokeWidth: 1.5,
opacity: 0.75
strokeOpacity: 0.75,
strokeWidth: 1.5
});

View File

@@ -11,9 +11,10 @@ goog.require('ol.style.SymbolizerLiteral');
/**
* @typedef {{fillColor: (string|undefined),
* fillOpacity: (number|undefined),
* strokeColor: (string|undefined),
* strokeWidth: (number|undefined),
* opacity: (number)}}
* strokeOpacity: (number|undefined),
* strokeWidth: (number|undefined)}}
*/
ol.style.PolygonLiteralOptions;
@@ -33,6 +34,13 @@ ol.style.PolygonLiteral = function(options) {
goog.asserts.assertString(options.fillColor, 'fillColor must be a string');
}
/** @type {number|undefined} */
this.fillOpacity = options.fillOpacity;
if (goog.isDef(options.fillOpacity)) {
goog.asserts.assertNumber(
options.fillOpacity, 'fillOpacity must be a number');
}
/** @type {string|undefined} */
this.strokeColor = options.strokeColor;
if (goog.isDef(this.strokeColor)) {
@@ -40,6 +48,13 @@ ol.style.PolygonLiteral = function(options) {
this.strokeColor, 'strokeColor must be a string');
}
/** @type {number|undefined} */
this.strokeOpacity = options.strokeOpacity;
if (goog.isDef(this.strokeOpacity)) {
goog.asserts.assertNumber(
this.strokeOpacity, 'strokeOpacity must be a number');
}
/** @type {number|undefined} */
this.strokeWidth = options.strokeWidth;
if (goog.isDef(this.strokeWidth)) {
@@ -47,14 +62,14 @@ ol.style.PolygonLiteral = function(options) {
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(options.opacity, 'opacity must be a number');
/** @type {number} */
this.opacity = options.opacity;
// fill and/or stroke properties must be defined
var fillDef = goog.isDef(this.fillColor) && goog.isDef(this.fillOpacity);
var strokeDef = goog.isDef(this.strokeColor) &&
goog.isDef(this.strokeOpacity) &&
goog.isDef(this.strokeWidth);
goog.asserts.assert(fillDef || strokeDef,
'Either fillColor and fillOpacity or ' +
'strokeColor and strokeOpacity and strokeWidth must be set');
};
goog.inherits(ol.style.PolygonLiteral, ol.style.SymbolizerLiteral);
@@ -65,9 +80,10 @@ goog.inherits(ol.style.PolygonLiteral, ol.style.SymbolizerLiteral);
*/
ol.style.PolygonLiteral.prototype.equals = function(polygonLiteral) {
return this.fillColor == polygonLiteral.fillColor &&
this.fillOpacity == polygonLiteral.fillOpacity &&
this.strokeColor == polygonLiteral.strokeColor &&
this.strokeWidth == polygonLiteral.strokeWidth &&
this.opacity == polygonLiteral.opacity;
this.strokeOpacity == polygonLiteral.strokeOpacity &&
this.strokeWidth == polygonLiteral.strokeWidth;
};
@@ -80,20 +96,54 @@ ol.style.PolygonLiteral.prototype.equals = function(polygonLiteral) {
ol.style.Polygon = function(options) {
goog.base(this);
// fill handling - if any fill property is supplied, use all defaults
var fillColor = null,
fillOpacity = null;
if (goog.isDefAndNotNull(options.fillColor) ||
goog.isDefAndNotNull(options.fillOpacity)) {
if (goog.isDefAndNotNull(options.fillColor)) {
fillColor = (options.fillColor instanceof ol.expr.Expression) ?
options.fillColor :
new ol.expr.Literal(options.fillColor);
} else {
fillColor = new ol.expr.Literal(
/** @type {string} */ (ol.style.PolygonDefaults.fillColor));
}
if (goog.isDefAndNotNull(options.fillOpacity)) {
fillOpacity = (options.fillOpacity instanceof ol.expr.Expression) ?
options.fillOpacity :
new ol.expr.Literal(options.fillOpacity);
} else {
fillOpacity = new ol.expr.Literal(
/** @type {number} */ (ol.style.PolygonDefaults.fillOpacity));
}
}
/**
* @type {ol.expr.Expression}
* @private
*/
this.fillColor_ = !goog.isDefAndNotNull(options.fillColor) ?
null :
(options.fillColor instanceof ol.expr.Expression) ?
options.fillColor : new ol.expr.Literal(options.fillColor);
this.fillColor_ = fillColor;
/**
* @type {ol.expr.Expression}
* @private
*/
this.fillOpacity_ = fillOpacity;
// stroke handling - if any stroke property is supplied, use defaults
var strokeColor = null,
strokeOpacity = null,
strokeWidth = null;
if (goog.isDefAndNotNull(options.strokeColor) ||
goog.isDefAndNotNull(options.strokeOpacity) ||
goog.isDefAndNotNull(options.strokeWidth)) {
if (goog.isDefAndNotNull(options.strokeColor)) {
@@ -105,6 +155,15 @@ ol.style.Polygon = function(options) {
/** @type {string} */ (ol.style.PolygonDefaults.strokeColor));
}
if (goog.isDefAndNotNull(options.strokeOpacity)) {
strokeOpacity = (options.strokeOpacity instanceof ol.expr.Expression) ?
options.strokeOpacity :
new ol.expr.Literal(options.strokeOpacity);
} else {
strokeOpacity = new ol.expr.Literal(
/** @type {number} */ (ol.style.PolygonDefaults.strokeOpacity));
}
if (goog.isDefAndNotNull(options.strokeWidth)) {
strokeWidth = (options.strokeWidth instanceof ol.expr.Expression) ?
options.strokeWidth :
@@ -113,6 +172,7 @@ ol.style.Polygon = function(options) {
strokeWidth = new ol.expr.Literal(
/** @type {number} */ (ol.style.PolygonDefaults.strokeWidth));
}
}
/**
@@ -125,21 +185,21 @@ ol.style.Polygon = function(options) {
* @type {ol.expr.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');
this.strokeOpacity_ = strokeOpacity;
/**
* @type {ol.expr.Expression}
* @private
*/
this.opacity_ = !goog.isDef(options.opacity) ?
new ol.expr.Literal(ol.style.PolygonDefaults.opacity) :
(options.opacity instanceof ol.expr.Expression) ?
options.opacity : new ol.expr.Literal(options.opacity);
this.strokeWidth_ = strokeWidth;
// one of stroke or fill can be null, both null is user error
var fill = !goog.isNull(this.fillColor_) && !goog.isNull(this.fillOpacity_);
var stroke = !goog.isNull(this.strokeColor_) &&
!goog.isNull(this.strokeOpacity_) &&
!goog.isNull(this.strokeWidth_);
goog.asserts.assert(fill || stroke,
'Stroke or fill properties must be provided');
};
goog.inherits(ol.style.Polygon, ol.style.Symbolizer);
@@ -157,41 +217,149 @@ ol.style.Polygon.prototype.createLiteral = function(opt_feature) {
goog.asserts.assertString(fillColor, 'fillColor must be a string');
}
var fillOpacity;
if (!goog.isNull(this.fillOpacity_)) {
fillOpacity = ol.expr.evaluateFeature(this.fillOpacity_, opt_feature);
goog.asserts.assertNumber(fillOpacity, 'fillOpacity must be a number');
}
var strokeColor;
if (!goog.isNull(this.strokeColor_)) {
strokeColor = ol.expr.evaluateFeature(this.strokeColor_, opt_feature);
goog.asserts.assertString(strokeColor, 'strokeColor must be a string');
}
var strokeOpacity;
if (!goog.isNull(this.strokeOpacity_)) {
strokeOpacity = ol.expr.evaluateFeature(this.strokeOpacity_, opt_feature);
goog.asserts.assertNumber(strokeOpacity, 'strokeOpacity must be a number');
}
var strokeWidth;
if (!goog.isNull(this.strokeWidth_)) {
strokeWidth = ol.expr.evaluateFeature(this.strokeWidth_, opt_feature);
goog.asserts.assertNumber(strokeWidth, 'strokeWidth must be a number');
}
goog.asserts.assert(
goog.isDef(fillColor) ||
(goog.isDef(strokeColor) && goog.isDef(strokeWidth)),
'either fillColor or strokeColor and strokeWidth must be defined');
var fill = goog.isDef(fillColor) && goog.isDef(fillOpacity);
var stroke = goog.isDef(strokeColor) && goog.isDef(strokeOpacity) &&
goog.isDef(strokeWidth);
var opacity = ol.expr.evaluateFeature(this.opacity_, opt_feature);
goog.asserts.assertNumber(opacity, 'opacity must be a number');
goog.asserts.assert(fill || stroke,
'either fill or stroke properties must be defined');
return new ol.style.PolygonLiteral({
fillColor: fillColor,
fillOpacity: fillOpacity,
strokeColor: strokeColor,
strokeWidth: strokeWidth,
opacity: opacity
strokeOpacity: strokeOpacity,
strokeWidth: strokeWidth
});
};
/**
* Get the fill color.
* @return {ol.expr.Expression} Fill color.
*/
ol.style.Polygon.prototype.getFillColor = function() {
return this.fillColor_;
};
/**
* Get the fill opacity.
* @return {ol.expr.Expression} Fill opacity.
*/
ol.style.Polygon.prototype.getFillOpacity = function() {
return this.fillOpacity_;
};
/**
* Get the stroke color.
* @return {ol.expr.Expression} Stroke color.
*/
ol.style.Polygon.prototype.getStrokeColor = function() {
return this.strokeColor_;
};
/**
* Get the stroke opacity.
* @return {ol.expr.Expression} Stroke opacity.
*/
ol.style.Polygon.prototype.getStrokeOpacity = function() {
return this.strokeOpacity_;
};
/**
* Get the stroke width.
* @return {ol.expr.Expression} Stroke width.
*/
ol.style.Polygon.prototype.getStrokeWidth = function() {
return this.strokeWidth_;
};
/**
* Set the fill color.
* @param {ol.expr.Expression} fillColor Fill color.
*/
ol.style.Polygon.prototype.setFillColor = function(fillColor) {
goog.asserts.assertInstanceof(fillColor, ol.expr.Expression);
this.fillColor_ = fillColor;
};
/**
* Set the fill opacity.
* @param {ol.expr.Expression} fillOpacity Fill opacity.
*/
ol.style.Polygon.prototype.setFillOpacity = function(fillOpacity) {
goog.asserts.assertInstanceof(fillOpacity, ol.expr.Expression);
this.fillOpacity_ = fillOpacity;
};
/**
* Set the stroke color.
* @param {ol.expr.Expression} strokeColor Stroke color.
*/
ol.style.Polygon.prototype.setStrokeColor = function(strokeColor) {
goog.asserts.assertInstanceof(strokeColor, ol.expr.Expression);
this.strokeColor_ = strokeColor;
};
/**
* Set the stroke opacity.
* @param {ol.expr.Expression} strokeOpacity Stroke opacity.
*/
ol.style.Polygon.prototype.setStrokeOpacity = function(strokeOpacity) {
goog.asserts.assertInstanceof(strokeOpacity, ol.expr.Expression);
this.strokeOpacity_ = strokeOpacity;
};
/**
* Set the stroke width.
* @param {ol.expr.Expression} strokeWidth Stroke width.
*/
ol.style.Polygon.prototype.setStrokeWidth = function(strokeWidth) {
goog.asserts.assertInstanceof(strokeWidth, ol.expr.Expression);
this.strokeWidth_ = strokeWidth;
};
/**
* @type {ol.style.PolygonLiteral}
*/
ol.style.PolygonDefaults = new ol.style.PolygonLiteral({
fillColor: '#ffffff',
fillOpacity: 0.4,
strokeColor: '#696969',
strokeWidth: 1.5,
opacity: 0.75
strokeOpacity: 0.8,
strokeWidth: 1.5
});

View File

@@ -22,9 +22,10 @@ ol.style.ShapeType = {
* @typedef {{type: (ol.style.ShapeType),
* size: (number),
* fillColor: (string|undefined),
* fillOpacity: (number|undefined),
* strokeColor: (string|undefined),
* strokeWidth: (number|undefined),
* opacity: (number)}}
* strokeOpacity: (number|undefined),
* strokeWidth: (number|undefined)}}
*/
ol.style.ShapeLiteralOptions;
@@ -51,6 +52,13 @@ ol.style.ShapeLiteral = function(options) {
goog.asserts.assertString(options.fillColor, 'fillColor must be a string');
}
/** @type {number|undefined} */
this.fillOpacity = options.fillOpacity;
if (goog.isDef(options.fillOpacity)) {
goog.asserts.assertNumber(
options.fillOpacity, 'fillOpacity must be a number');
}
/** @type {string|undefined} */
this.strokeColor = options.strokeColor;
if (goog.isDef(this.strokeColor)) {
@@ -58,6 +66,13 @@ ol.style.ShapeLiteral = function(options) {
this.strokeColor, 'strokeColor must be a string');
}
/** @type {number|undefined} */
this.strokeOpacity = options.strokeOpacity;
if (goog.isDef(this.strokeOpacity)) {
goog.asserts.assertNumber(
this.strokeOpacity, 'strokeOpacity must be a number');
}
/** @type {number|undefined} */
this.strokeWidth = options.strokeWidth;
if (goog.isDef(this.strokeWidth)) {
@@ -65,14 +80,14 @@ ol.style.ShapeLiteral = function(options) {
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(options.opacity, 'opacity must be a number');
/** @type {number} */
this.opacity = options.opacity;
// fill and/or stroke properties must be defined
var fillDef = goog.isDef(this.fillColor) && goog.isDef(this.fillOpacity);
var strokeDef = goog.isDef(this.strokeColor) &&
goog.isDef(this.strokeOpacity) &&
goog.isDef(this.strokeWidth);
goog.asserts.assert(fillDef || strokeDef,
'Either fillColor and fillOpacity or ' +
'strokeColor and strokeOpacity and strokeWidth must be set');
};
goog.inherits(ol.style.ShapeLiteral, ol.style.PointLiteral);
@@ -85,9 +100,10 @@ ol.style.ShapeLiteral.prototype.equals = function(shapeLiteral) {
return this.type == shapeLiteral.type &&
this.size == shapeLiteral.size &&
this.fillColor == shapeLiteral.fillColor &&
this.fillOpacity == shapeLiteral.fillOpacity &&
this.strokeColor == shapeLiteral.strokeColor &&
this.strokeWidth == shapeLiteral.strokeWidth &&
this.opacity == shapeLiteral.opacity;
this.strokeOpacity == shapeLiteral.strokeOpacity &&
this.strokeWidth == shapeLiteral.strokeWidth;
};
@@ -110,25 +126,58 @@ ol.style.Shape = function(options) {
* @type {ol.expr.Expression}
* @private
*/
this.size_ = !goog.isDef(options.size) ?
this.size_ = !goog.isDefAndNotNull(options.size) ?
new ol.expr.Literal(ol.style.ShapeDefaults.size) :
(options.size instanceof ol.expr.Expression) ?
options.size : new ol.expr.Literal(options.size);
// fill handling - if any fill property is supplied, use all defaults
var fillColor = null,
fillOpacity = null;
if (goog.isDefAndNotNull(options.fillColor) ||
goog.isDefAndNotNull(options.fillOpacity)) {
if (goog.isDefAndNotNull(options.fillColor)) {
fillColor = (options.fillColor instanceof ol.expr.Expression) ?
options.fillColor :
new ol.expr.Literal(options.fillColor);
} else {
fillColor = new ol.expr.Literal(
/** @type {string} */ (ol.style.ShapeDefaults.fillColor));
}
if (goog.isDefAndNotNull(options.fillOpacity)) {
fillOpacity = (options.fillOpacity instanceof ol.expr.Expression) ?
options.fillOpacity :
new ol.expr.Literal(options.fillOpacity);
} else {
fillOpacity = new ol.expr.Literal(
/** @type {number} */ (ol.style.ShapeDefaults.fillOpacity));
}
}
/**
* @type {ol.expr.Expression}
* @private
*/
this.fillColor_ = !goog.isDefAndNotNull(options.fillColor) ?
null :
(options.fillColor instanceof ol.expr.Expression) ?
options.fillColor : new ol.expr.Literal(options.fillColor);
this.fillColor_ = fillColor;
/**
* @type {ol.expr.Expression}
* @private
*/
this.fillOpacity_ = fillOpacity;
// stroke handling - if any stroke property is supplied, use defaults
var strokeColor = null,
strokeOpacity = null,
strokeWidth = null;
if (goog.isDefAndNotNull(options.strokeColor) ||
goog.isDefAndNotNull(options.strokeOpacity) ||
goog.isDefAndNotNull(options.strokeWidth)) {
if (goog.isDefAndNotNull(options.strokeColor)) {
@@ -140,6 +189,15 @@ ol.style.Shape = function(options) {
/** @type {string} */ (ol.style.ShapeDefaults.strokeColor));
}
if (goog.isDefAndNotNull(options.strokeOpacity)) {
strokeOpacity = (options.strokeOpacity instanceof ol.expr.Expression) ?
options.strokeOpacity :
new ol.expr.Literal(options.strokeOpacity);
} else {
strokeOpacity = new ol.expr.Literal(
/** @type {number} */ (ol.style.ShapeDefaults.strokeOpacity));
}
if (goog.isDefAndNotNull(options.strokeWidth)) {
strokeWidth = (options.strokeWidth instanceof ol.expr.Expression) ?
options.strokeWidth :
@@ -161,21 +219,21 @@ ol.style.Shape = function(options) {
* @type {ol.expr.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');
this.strokeOpacity_ = strokeOpacity;
/**
* @type {ol.expr.Expression}
* @private
*/
this.opacity_ = !goog.isDef(options.opacity) ?
new ol.expr.Literal(ol.style.ShapeDefaults.opacity) :
(options.opacity instanceof ol.expr.Expression) ?
options.opacity : new ol.expr.Literal(options.opacity);
this.strokeWidth_ = strokeWidth;
// one of stroke or fill can be null, both null is user error
var fill = !goog.isNull(this.fillColor_) && !goog.isNull(this.fillOpacity_);
var stroke = !goog.isNull(this.strokeColor_) &&
!goog.isNull(this.strokeOpacity_) &&
!goog.isNull(this.strokeWidth_);
goog.asserts.assert(fill || stroke,
'Stroke or fill properties must be provided');
};
@@ -195,37 +253,181 @@ ol.style.Shape.prototype.createLiteral = function(opt_feature) {
goog.asserts.assertString(fillColor, 'fillColor must be a string');
}
var fillOpacity;
if (!goog.isNull(this.fillOpacity_)) {
fillOpacity = ol.expr.evaluateFeature(this.fillOpacity_, opt_feature);
goog.asserts.assertNumber(fillOpacity, 'fillOpacity must be a number');
}
var strokeColor;
if (!goog.isNull(this.strokeColor_)) {
strokeColor = ol.expr.evaluateFeature(this.strokeColor_, opt_feature);
goog.asserts.assertString(strokeColor, 'strokeColor must be a string');
}
var strokeOpacity;
if (!goog.isNull(this.strokeOpacity_)) {
strokeOpacity = ol.expr.evaluateFeature(this.strokeOpacity_, opt_feature);
goog.asserts.assertNumber(strokeOpacity, 'strokeOpacity must be a number');
}
var strokeWidth;
if (!goog.isNull(this.strokeWidth_)) {
strokeWidth = ol.expr.evaluateFeature(this.strokeWidth_, opt_feature);
goog.asserts.assertNumber(strokeWidth, 'strokeWidth must be a number');
}
goog.asserts.assert(
goog.isDef(fillColor) ||
(goog.isDef(strokeColor) && goog.isDef(strokeWidth)),
'either fillColor or strokeColor and strokeWidth must be defined');
var fill = goog.isDef(fillColor) && goog.isDef(fillOpacity);
var stroke = goog.isDef(strokeColor) && goog.isDef(strokeOpacity) &&
goog.isDef(strokeWidth);
var opacity = ol.expr.evaluateFeature(this.opacity_, opt_feature);
goog.asserts.assertNumber(opacity, 'opacity must be a number');
goog.asserts.assert(fill || stroke,
'either fill or stroke properties must be defined');
return new ol.style.ShapeLiteral({
type: this.type_,
size: size,
fillColor: fillColor,
fillOpacity: fillOpacity,
strokeColor: strokeColor,
strokeWidth: strokeWidth,
opacity: opacity
strokeOpacity: strokeOpacity,
strokeWidth: strokeWidth
});
};
/**
* Get the fill color.
* @return {ol.expr.Expression} Fill color.
*/
ol.style.Shape.prototype.getFillColor = function() {
return this.fillColor_;
};
/**
* Get the fill opacity.
* @return {ol.expr.Expression} Fill opacity.
*/
ol.style.Shape.prototype.getFillOpacity = function() {
return this.fillOpacity_;
};
/**
* Get the shape size.
* @return {ol.expr.Expression} Shape size.
*/
ol.style.Shape.prototype.getSize = function() {
return this.size_;
};
/**
* Get the stroke color.
* @return {ol.expr.Expression} Stroke color.
*/
ol.style.Shape.prototype.getStrokeColor = function() {
return this.strokeColor_;
};
/**
* Get the stroke opacity.
* @return {ol.expr.Expression} Stroke opacity.
*/
ol.style.Shape.prototype.getStrokeOpacity = function() {
return this.strokeOpacity_;
};
/**
* Get the stroke width.
* @return {ol.expr.Expression} Stroke width.
*/
ol.style.Shape.prototype.getStrokeWidth = function() {
return this.strokeWidth_;
};
/**
* Get the shape type.
* @return {ol.style.ShapeType} Shape type.
*/
ol.style.Shape.prototype.getType = function() {
return this.type_;
};
/**
* Set the fill color.
* @param {ol.expr.Expression} fillColor Fill color.
*/
ol.style.Shape.prototype.setFillColor = function(fillColor) {
goog.asserts.assertInstanceof(fillColor, ol.expr.Expression);
this.fillColor_ = fillColor;
};
/**
* Set the fill opacity.
* @param {ol.expr.Expression} fillOpacity Fill opacity.
*/
ol.style.Shape.prototype.setFillOpacity = function(fillOpacity) {
goog.asserts.assertInstanceof(fillOpacity, ol.expr.Expression);
this.fillOpacity_ = fillOpacity;
};
/**
* Set the shape size.
* @param {ol.expr.Expression} size Shape size.
*/
ol.style.Shape.prototype.setSize = function(size) {
goog.asserts.assertInstanceof(size, ol.expr.Expression);
this.size_ = size;
};
/**
* Set the stroke color.
* @param {ol.expr.Expression} strokeColor Stroke color.
*/
ol.style.Shape.prototype.setStrokeColor = function(strokeColor) {
goog.asserts.assertInstanceof(strokeColor, ol.expr.Expression);
this.strokeColor_ = strokeColor;
};
/**
* Set the stroke opacity.
* @param {ol.expr.Expression} strokeOpacity Stroke opacity.
*/
ol.style.Shape.prototype.setStrokeOpacity = function(strokeOpacity) {
goog.asserts.assertInstanceof(strokeOpacity, ol.expr.Expression);
this.strokeOpacity_ = strokeOpacity;
};
/**
* Set the stroke width.
* @param {ol.expr.Expression} strokeWidth Stroke width.
*/
ol.style.Shape.prototype.setStrokeWidth = function(strokeWidth) {
goog.asserts.assertInstanceof(strokeWidth, ol.expr.Expression);
this.strokeWidth_ = strokeWidth;
};
/**
* Set the shape type.
* @param {ol.style.ShapeType} type Shape type.
*/
ol.style.Shape.prototype.setType = function(type) {
this.type_ = type;
};
/**
* @type {ol.style.ShapeLiteral}
*/
@@ -233,7 +435,8 @@ ol.style.ShapeDefaults = new ol.style.ShapeLiteral({
type: ol.style.ShapeType.CIRCLE,
size: 5,
fillColor: '#ffffff',
fillOpacity: 0.4,
strokeColor: '#696969',
strokeWidth: 1.5,
opacity: 0.75
strokeOpacity: 0.8,
strokeWidth: 1.5
});

View File

@@ -148,6 +148,101 @@ ol.style.Text.prototype.createLiteral = function(opt_feature) {
};
/**
* Get the font color.
* @return {ol.expr.Expression} Font color.
*/
ol.style.Text.prototype.getColor = function() {
return this.color_;
};
/**
* Get the font family.
* @return {ol.expr.Expression} Font family.
*/
ol.style.Text.prototype.getFontFamily = function() {
return this.fontFamily_;
};
/**
* Get the font size.
* @return {ol.expr.Expression} Font size.
*/
ol.style.Text.prototype.getFontSize = function() {
return this.fontSize_;
};
/**
* Get the opacity.
* @return {ol.expr.Expression} Opacity.
*/
ol.style.Text.prototype.getOpacity = function() {
return this.opacity_;
};
/**
* Get the text.
* @return {ol.expr.Expression} Text.
*/
ol.style.Text.prototype.getText = function() {
return this.text_;
};
/**
* Set the font color.
* @param {ol.expr.Expression} color Font color.
*/
ol.style.Text.prototype.setColor = function(color) {
goog.asserts.assertInstanceof(color, ol.expr.Expression);
this.color_ = color;
};
/**
* Set the font family.
* @param {ol.expr.Expression} fontFamily Font family.
*/
ol.style.Text.prototype.setFontFamily = function(fontFamily) {
goog.asserts.assertInstanceof(fontFamily, ol.expr.Expression);
this.fontFamily_ = fontFamily;
};
/**
* Set the font size.
* @param {ol.expr.Expression} fontSize Font size.
*/
ol.style.Text.prototype.setFontSize = function(fontSize) {
goog.asserts.assertInstanceof(fontSize, ol.expr.Expression);
this.fontSize_ = fontSize;
};
/**
* Set the opacity.
* @param {ol.expr.Expression} opacity Opacity.
*/
ol.style.Text.prototype.setOpacity = function(opacity) {
goog.asserts.assertInstanceof(opacity, ol.expr.Expression);
this.opacity_ = opacity;
};
/**
* Set the text.
* @param {ol.expr.Expression} text Text.
*/
ol.style.Text.prototype.setText = function(text) {
goog.asserts.assertInstanceof(text, ol.expr.Expression);
this.text_ = text;
};
/**
* @type {ol.style.TextLiteral}
*/

View File

@@ -1,6 +1,8 @@
goog.provide('ol.TileCache');
goog.require('goog.asserts');
goog.require('ol.Tile');
goog.require('ol.TileCoord');
goog.require('ol.TileRange');
goog.require('ol.structs.LRUCache');
@@ -47,6 +49,9 @@ ol.TileCache.prototype.expireCache = function(usedTiles) {
var tile, zKey;
while (this.canExpireCache()) {
tile = /** @type {ol.Tile} */ (this.peekLast());
// TODO: Enforce ol.Tile in ol.TileCache#set
goog.asserts.assert(tile instanceof ol.Tile,
'ol.TileCache#expireCache only works with ol.Tile values.');
zKey = tile.tileCoord.z.toString();
if (zKey in usedTiles && usedTiles[zKey].contains(tile.tileCoord)) {
break;
@@ -55,3 +60,21 @@ ol.TileCache.prototype.expireCache = function(usedTiles) {
}
}
};
/**
* Remove a tile range from the cache, e.g. to invalidate tiles.
* @param {ol.TileRange} tileRange The tile range to prune.
*/
ol.TileCache.prototype.pruneTileRange = function(tileRange) {
var i = this.getCount(),
key;
while (i--) {
key = this.peekLastKey();
if (tileRange.contains(ol.TileCoord.createFromString(key))) {
this.pop();
} else {
this.get(key);
}
}
};

View File

@@ -1 +1,5 @@
@exportClass ol.tilegrid.TileGrid ol.tilegrid.TileGridOptions
@exportProperty ol.tilegrid.TileGrid.prototype.getMinZoom
@exportProperty ol.tilegrid.TileGrid.prototype.getOrigin
@exportProperty ol.tilegrid.TileGrid.prototype.getResolutions
@exportProperty ol.tilegrid.TileGrid.prototype.getTileSize

View File

@@ -1 +1,2 @@
@exportClass ol.tilegrid.WMTS ol.tilegrid.WMTSOptions
@exportProperty ol.tilegrid.WMTS.prototype.getMatrixIds

View File

@@ -66,15 +66,31 @@ ol.tilegrid.WMTS.createFromCapabilitiesMatrixSet =
var matrixIds = [];
var origins = [];
var tileSizes = [];
var projection = ol.proj.get(matrixSet['supportedCRS']);
var supportedCRSPropName = 'supportedCRS';
var matrixIdsPropName = 'matrixIds';
var identifierPropName = 'identifier';
var scaleDenominatorPropName = 'scaleDenominator';
var topLeftCornerPropName = 'topLeftCorner';
var tileWidthPropName = 'tileWidth';
var tileHeightPropName = 'tileHeight';
var projection = ol.proj.get(matrixSet[supportedCRSPropName]);
var metersPerUnit = projection.getMetersPerUnit();
goog.array.forEach(matrixSet['matrixIds'], function(elt, index, array) {
matrixIds.push(elt['identifier']);
origins.push(elt['topLeftCorner']);
resolutions.push(elt['scaleDenominator'] * 0.28E-3 / metersPerUnit);
tileSizes.push([elt['tileWidth'], elt['tileHeight']]);
goog.array.sort(matrixSet[matrixIdsPropName], function(a, b) {
return b[scaleDenominatorPropName] - a[scaleDenominatorPropName];
});
goog.array.forEach(matrixSet[matrixIdsPropName],
function(elt, index, array) {
matrixIds.push(elt[identifierPropName]);
origins.push(elt[topLeftCornerPropName]);
resolutions.push(elt[scaleDenominatorPropName] * 0.28E-3 /
metersPerUnit);
tileSizes.push([elt[tileWidthPropName], elt[tileHeightPropName]]);
});
return new ol.tilegrid.WMTS({
origins: origins,
resolutions: resolutions,

View File

@@ -48,7 +48,7 @@ ol.tilegrid.XYZ.prototype.createTileCoordTransform = function(opt_options) {
if (goog.isDef(options.extent)) {
tileRangeByZ = new Array(maxZ + 1);
var z;
for (z = 0; z < maxZ; ++z) {
for (z = 0; z <= maxZ; ++z) {
if (z < minZ) {
tileRangeByZ[z] = null;
} else {

View File

@@ -4,3 +4,5 @@
@exportProperty ol.View2D.prototype.constrainRotation
@exportProperty ol.View2D.prototype.fitExtent
@exportProperty ol.View2D.prototype.getView2D
@exportProperty ol.View2D.prototype.getZoom
@exportProperty ol.View2D.prototype.setZoom

View File

@@ -32,13 +32,51 @@ ol.View2DProperty = {
/**
* Create a new View2D, a View2D manages properties such as center,
* projection, resolution and rotation.
* @class
* An ol.View2D object represents a simple 2D view of the map.
*
* Example:
* This is the object to act upon to change the center, resolution,
* and rotation of the map.
*
* // to get the current extent
* map.getView().getView2D().calculateExtent(map.getSize())
* ### The view states
*
* An `ol.View2D` is determined by three states: `center`, `resolution`,
* and `rotation`. To each state corresponds a getter and a setter. E.g.
* `getCenter` and `setCenter` for the `center` state.
*
* An `ol.View2D` has a `projection`. The projection determines the
* coordinate system of the center, and its units determine the units of the
* resolution (projection units per pixel). The default projection is
* Spherical Mercator (EPSG:3857).
*
* ### The constraints
*
* `setCenter`, `setResolution` and `setRotation` can be used to change the
* states of the view. Any value can be passed to the setters. And the value
* that is passed to a setter will effectively be the value set in the view,
* and returned by the corresponding getter.
*
* But an `ol.View2D` object also has a *resolution constraint* and a
* *rotation constraint*. There's currently no *center constraint*, but
* this may change in the future.
*
* As said above no constraints are applied when the setters are used to set
* new states for the view. Applying constraints is done explicitly through
* the use of the `constrain*` functions (`constrainResolution` and
* `constrainRotation`).
*
* The main users of the constraints are the interactions and the
* controls. For example, double-clicking on the map changes the view to
* the "next" resolution. And releasing the fingers after pinch-zooming
* snaps to the closest resolution (with an animation).
*
* So the *resolution constraint* snaps to specific resolutions. It is
* determined by the following options: `resolutions`, `maxResolution`,
* `maxZoom`, and `zoomFactor`. If `resolutions` is set, the other three
* options are ignored. See {@link ol.View2DOptions} for more information.
*
* The *rotation constaint* is currently not configurable. It snaps the
* rotation value to zero when approaching the horizontal.
*
* @constructor
* @implements {ol.IView2D}
@@ -59,21 +97,22 @@ ol.View2D = function(opt_options) {
values[ol.View2DProperty.PROJECTION] = ol.proj.createProjection(
options.projection, 'EPSG:3857');
var parts = ol.View2D.createResolutionConstraint_(options);
var resolutionConstraintInfo = ol.View2D.createResolutionConstraint_(
options);
/**
* @private
* @type {number}
*/
this.maxResolution_ = parts[1];
this.maxResolution_ = resolutionConstraintInfo.maxResolution;
/**
* @private
* @type {number}
*/
this.minResolution_ = parts[2];
this.minResolution_ = resolutionConstraintInfo.minResolution;
var resolutionConstraint = parts[0];
var resolutionConstraint = resolutionConstraintInfo.constraint;
var rotationConstraint = ol.View2D.createRotationConstraint_(options);
/**
@@ -86,7 +125,7 @@ ol.View2D = function(opt_options) {
if (goog.isDef(options.resolution)) {
values[ol.View2DProperty.RESOLUTION] = options.resolution;
} else if (goog.isDef(options.zoom)) {
values[ol.View2DProperty.RESOLUTION] = resolutionConstraint(
values[ol.View2DProperty.RESOLUTION] = this.constrainResolution(
this.maxResolution_, options.zoom);
}
values[ol.View2DProperty.ROTATION] =
@@ -324,6 +363,31 @@ ol.View2D.prototype.getView3D = function() {
};
/**
* Get the current zoom level. Return undefined if the current
* resolution is undefined or not a "constrained resolution".
* @return {number|undefined} Zoom.
*/
ol.View2D.prototype.getZoom = function() {
var zoom;
var resolution = this.getResolution();
if (goog.isDef(resolution)) {
var res, z = 0;
do {
res = this.constrainResolution(this.maxResolution_, z);
if (res == resolution) {
zoom = z;
break;
}
++z;
} while (res > this.minResolution_);
}
return zoom;
};
/**
* Fit the given extent based on the given map size.
* @param {ol.Extent} extent Extent.
@@ -398,11 +462,21 @@ goog.exportProperty(
ol.View2D.prototype.setRotation);
/**
* Zoom to a specific zoom level.
* @param {number} zoom Zoom level.
*/
ol.View2D.prototype.setZoom = function(zoom) {
var resolution = this.constrainResolution(this.maxResolution_, zoom, 0);
this.setResolution(resolution);
};
/**
* @private
* @param {ol.View2DOptions} options View2D options.
* @return {Array} Array of three elements: the resolution constraint,
* maxResolution, and minResolution.
* @return {{constraint: ol.ResolutionConstraintType, maxResolution: number,
* minResolution: number}}
*/
ol.View2D.createResolutionConstraint_ = function(options) {
var resolutionConstraint;
@@ -440,7 +514,8 @@ ol.View2D.createResolutionConstraint_ = function(options) {
resolutionConstraint = ol.ResolutionConstraint.createSnapToPower(
zoomFactor, maxResolution, maxZoom);
}
return [resolutionConstraint, maxResolution, minResolution];
return {constraint: resolutionConstraint, maxResolution: maxResolution,
minResolution: minResolution};
};