diff --git a/build/loader_hosted_examples.js b/build/loader_hosted_examples.js
index 3ec22aa5e2..9afe49715f 100644
--- a/build/loader_hosted_examples.js
+++ b/build/loader_hosted_examples.js
@@ -6,8 +6,8 @@
* This loader is used for the hosted examples. It is used in place of the
* development loader (examples/loader.js).
*
- * ol.css and ol.js are built with Plovr/Closure, based build/ol.json.
- * (`make build` should build them). They are located in the ../build/
+ * ol.css and ol.js are built with Plovr/Closure, based on build/ol.json.
+ * (`build.py build` builds them). They are located in the ../build/
* directory, relatively to this script.
*
* The script should be named loader.js. So it needs to be renamed to
diff --git a/css/ol.css b/css/ol.css
index eca80d969c..79fec30bae 100644
--- a/css/ol.css
+++ b/css/ol.css
@@ -5,9 +5,7 @@
color: #eeeeee;
bottom: 0;
right: 0;
- background: #130085; /* @alternate */
background: rgba(0,60,136,0.3);
- filter: alpha(opacity=30);
font-family: 'Lucida Grande',Verdana,Geneva,Lucida,Arial,Helvetica,sans-serif;
padding: 2px 4px;
}
@@ -60,14 +58,10 @@
height: 22px;
width: 22px;
line-height: 19px;
- background: #130085; /* @alternate */
background: rgba(0,60,136,0.5);
- filter: alpha(opacity=80);
}
.ol-zoom a:hover {
- background: #130085; /* @alternate */
background: rgba(0,60,136,0.7);
- filter: alpha(opacity=100);
}
@media only screen and (max-width:600px) {
.ol-zoom a:hover {
diff --git a/examples/side-by-side.js b/examples/side-by-side.js
index b5d108b0df..661d1ebb79 100644
--- a/examples/side-by-side.js
+++ b/examples/side-by-side.js
@@ -131,7 +131,7 @@ keyboardInteraction.addCallback('l', function() {
view.setCenter(LONDON);
});
keyboardInteraction.addCallback('L', function() {
- var start = goog.now();
+ var start = +new Date();
var duration = 5000;
var bounce = ol.animation.bounce({
resolution: 2 * view.getResolution(),
@@ -166,7 +166,7 @@ keyboardInteraction.addCallback('m', function() {
view.setCenter(MOSCOW);
});
keyboardInteraction.addCallback('M', function() {
- var start = goog.now();
+ var start = +new Date();
var duration = 5000;
var bounce = ol.animation.bounce({
resolution: 2 * view.getResolution(),
diff --git a/examples/standalone/full-screen-standalone.html b/examples/standalone/full-screen-standalone.html
deleted file mode 100644
index afb0f97f38..0000000000
--- a/examples/standalone/full-screen-standalone.html
+++ /dev/null
@@ -1,23 +0,0 @@
-
-
-
-
-
-
-
-
- ol3 full-screen demo
-
-
-
-
-
-
-
diff --git a/examples/standalone/overlay-and-popup-standalone.html b/examples/standalone/overlay-and-popup-standalone.html
deleted file mode 100644
index e1293b1c54..0000000000
--- a/examples/standalone/overlay-and-popup-standalone.html
+++ /dev/null
@@ -1,82 +0,0 @@
-
-
-
-
-
-
-
-
- ol3 overlay-and-popup demo
-
-
-
-
-
-
-
diff --git a/examples/standalone/side-by-side-standalone.html b/examples/standalone/side-by-side-standalone.html
deleted file mode 100644
index e28c0425a7..0000000000
--- a/examples/standalone/side-by-side-standalone.html
+++ /dev/null
@@ -1,71 +0,0 @@
-
-
-
-
-
-
-
- ol3 side-by-side demo
-
-
-
- ol3 side-by-side demo
-
-
- DOM
- WebGL
-
-
-
-
-
-
-
-
-
-
-
-
- Pan:
- drag, arrow keys
-
-
- Zoom:
- double-click, Shift+double-click, mouse wheel, +/- keys; Shift+drag
-
-
- Rotate:
- Alt+drag, r to reset
-
-
- Brightness/contrast:
- b/B/c/C keys (WebGL only)
-
-
- Hue/saturation:
- h/H/s/S keys (WebGL only)
-
-
- Opacity:
- o/O keys
-
-
- Visibility:
- v/V keys
-
-
- Reset
- 0 key
-
-
- Notes: The two maps share the same center, resolution, rotation and layers.
-
-
-
diff --git a/examples/wms-custom-proj.js b/examples/wms-custom-proj.js
index fea7b563dd..20b2b90072 100644
--- a/examples/wms-custom-proj.js
+++ b/examples/wms-custom-proj.js
@@ -29,9 +29,8 @@ ol.Projection.addProjection(epsg21781);
// We give the single image source a set of resolutions. This prevents the
// source from requesting images of arbitrary resolutions.
var projectionExtent = epsg21781.getExtent();
-var maxResolution = Math.max(
- projectionExtent.maxX - projectionExtent.minX,
- projectionExtent.maxY - projectionExtent.minY) / 256;
+var maxResolution = Math.max(projectionExtent.getWidth(),
+ projectionExtent.getHeight()) / 256;
var resolutions = new Array(10);
for (var i = 0; i < 10; ++i) {
resolutions[i] = maxResolution / Math.pow(2.0, i);
diff --git a/externs/tilejson.js b/externs/tilejson.js
index 5927c479ee..6e982cc325 100644
--- a/externs/tilejson.js
+++ b/externs/tilejson.js
@@ -66,7 +66,7 @@ TileJSON.prototype.tiles;
/**
- * @type {!Array.}
+ * @type {!Array.|undefined}
*/
TileJSON.prototype.grids;
diff --git a/src/objectliterals.exports b/src/objectliterals.exports
index 0e24207a11..4af5ad024f 100644
--- a/src/objectliterals.exports
+++ b/src/objectliterals.exports
@@ -12,6 +12,8 @@
@exportObjectLiteralProperty ol.MapOptions.renderers Array.|undefined
@exportObjectLiteralProperty ol.MapOptions.shiftDragZoom boolean|undefined
@exportObjectLiteralProperty ol.MapOptions.target Element|string
+@exportObjectLiteralProperty ol.MapOptions.touchPan boolean|undefined
+@exportObjectLiteralProperty ol.MapOptions.touchRotateZoom boolean|undefined
@exportObjectLiteralProperty ol.MapOptions.view ol.IView|undefined
@exportObjectLiteralProperty ol.MapOptions.zoomControl boolean|undefined
@exportObjectLiteralProperty ol.MapOptions.zoomDelta number|undefined
diff --git a/src/ol/animation.exports b/src/ol/animation.exports
index 98207b2e1a..4a8819704d 100644
--- a/src/ol/animation.exports
+++ b/src/ol/animation.exports
@@ -2,3 +2,4 @@
@exportProperty ol.animation.bounce
@exportProperty ol.animation.pan
@exportProperty ol.animation.rotate
+@exportProperty ol.animation.zoom
diff --git a/src/ol/easing.exports b/src/ol/easing.exports
new file mode 100644
index 0000000000..62418771ad
--- /dev/null
+++ b/src/ol/easing.exports
@@ -0,0 +1,5 @@
+@exportSymbol ol.easing
+@exportProperty ol.easing.linear
+@exportProperty ol.easing.upAndDown
+@exportProperty ol.easing.elastic
+@exportProperty ol.easing.bounce
diff --git a/src/ol/extent.exports b/src/ol/extent.exports
index 23e1785d4f..b52ee8007a 100644
--- a/src/ol/extent.exports
+++ b/src/ol/extent.exports
@@ -1,2 +1,3 @@
@exportSymbol ol.Extent
-
+@exportProperty ol.Extent.prototype.getHeight
+@exportProperty ol.Extent.prototype.getWidth
diff --git a/src/imageurlfunction.js b/src/ol/imageurlfunction.js
similarity index 96%
rename from src/imageurlfunction.js
rename to src/ol/imageurlfunction.js
index bb328819eb..ebaec5c427 100644
--- a/src/imageurlfunction.js
+++ b/src/ol/imageurlfunction.js
@@ -1,6 +1,7 @@
goog.provide('ol.ImageUrlFunction');
goog.provide('ol.ImageUrlFunctionType');
+goog.require('goog.uri.utils');
goog.require('ol.Extent');
goog.require('ol.Size');
diff --git a/src/ol/interaction/touchinteraction.js b/src/ol/interaction/touchinteraction.js
new file mode 100644
index 0000000000..c71d5997de
--- /dev/null
+++ b/src/ol/interaction/touchinteraction.js
@@ -0,0 +1,119 @@
+
+goog.provide('ol.interaction.Touch');
+
+goog.require('goog.functions');
+goog.require('ol.MapBrowserEvent');
+goog.require('ol.MapBrowserEvent.EventType');
+goog.require('ol.Pixel');
+goog.require('ol.interaction.Interaction');
+
+
+
+/**
+ * @constructor
+ * @extends {ol.interaction.Interaction}
+ */
+ol.interaction.Touch = function() {
+
+ goog.base(this);
+
+ /**
+ * @type {boolean}
+ * @private
+ */
+ this.handled_ = false;
+
+ /**
+ * @type {Object}
+ * @private
+ */
+ this.trackedTouches_ = {};
+
+ /**
+ * @type {Array.}
+ */
+ this.targetTouches = [];
+
+};
+goog.inherits(ol.interaction.Touch, ol.interaction.Interaction);
+
+
+/**
+ * @param {Array.} touches TouchEvents.
+ * @return {ol.Pixel} Centroid pixel.
+ */
+ol.interaction.Touch.centroid = function(touches) {
+ var length = touches.length;
+ var clientX = 0;
+ var clientY = 0;
+ for (var i = 0; i < length; i++) {
+ clientX += touches[i].clientX;
+ clientY += touches[i].clientY;
+ }
+ return new ol.Pixel(clientX / length, clientY / length);
+};
+
+
+/**
+ * @param {ol.MapBrowserEvent} mapBrowserEvent Event.
+ * @private
+ */
+ol.interaction.Touch.prototype.updateTrackedTouches_ =
+ function(mapBrowserEvent) {
+ var event = mapBrowserEvent.browserEvent.getBrowserEvent();
+ if (goog.isDef(event.targetTouches)) {
+ // W3C touch events
+ this.targetTouches = event.targetTouches;
+ } else {
+ // IE pointer event
+ if (mapBrowserEvent.type == ol.MapBrowserEvent.EventType.TOUCHEND) {
+ delete this.trackedTouches_[event.pointerId];
+ } else {
+ this.trackedTouches_[event.pointerId] = event;
+ }
+ this.targetTouches = goog.object.getValues(this.trackedTouches_);
+ }
+};
+
+
+/**
+ * @param {ol.MapBrowserEvent} mapBrowserEvent Event.
+ * @protected
+ */
+ol.interaction.Touch.prototype.handleTouchMove = goog.nullFunction;
+
+
+/**
+ * @param {ol.MapBrowserEvent} mapBrowserEvent Event.
+ * @protected
+ * @return {boolean} Capture dragging.
+ */
+ol.interaction.Touch.prototype.handleTouchEnd = goog.functions.FALSE;
+
+
+/**
+ * @param {ol.MapBrowserEvent} mapBrowserEvent Event.
+ * @protected
+ * @return {boolean} Capture dragging.
+ */
+ol.interaction.Touch.prototype.handleTouchStart = goog.functions.FALSE;
+
+
+/**
+ * @inheritDoc
+ */
+ol.interaction.Touch.prototype.handleMapBrowserEvent =
+ function(mapBrowserEvent) {
+ var browserEvent = mapBrowserEvent.browserEvent.getBrowserEvent();
+ this.updateTrackedTouches_(mapBrowserEvent);
+ if (this.handled_) {
+ if (mapBrowserEvent.type == ol.MapBrowserEvent.EventType.TOUCHMOVE) {
+ this.handleTouchMove(mapBrowserEvent);
+ } else if (mapBrowserEvent.type == ol.MapBrowserEvent.EventType.TOUCHEND) {
+ this.handled_ = this.handleTouchEnd(mapBrowserEvent);
+ }
+ }
+ if (mapBrowserEvent.type == ol.MapBrowserEvent.EventType.TOUCHSTART) {
+ this.handled_ = this.handleTouchStart(mapBrowserEvent);
+ }
+};
diff --git a/src/ol/interaction/touchpaninteraction.js b/src/ol/interaction/touchpaninteraction.js
new file mode 100644
index 0000000000..0c21c78c4b
--- /dev/null
+++ b/src/ol/interaction/touchpaninteraction.js
@@ -0,0 +1,116 @@
+// FIXME works for View2D only
+// FIXME opt_kinetic param
+goog.provide('ol.interaction.TouchPan');
+
+goog.require('goog.asserts');
+goog.require('ol.Coordinate');
+goog.require('ol.Kinetic');
+goog.require('ol.Pixel');
+goog.require('ol.PreRenderFunction');
+goog.require('ol.View');
+goog.require('ol.ViewHint');
+goog.require('ol.interaction.Touch');
+
+
+
+/**
+ * @constructor
+ * @extends {ol.interaction.Touch}
+ */
+ol.interaction.TouchPan = function() {
+
+ goog.base(this);
+
+ /**
+ * @private
+ * @type {ol.Kinetic}
+ */
+ this.kinetic_ = new ol.Kinetic(-0.005, 0.05, 100);
+
+ /**
+ * @private
+ * @type {?ol.PreRenderFunction}
+ */
+ this.kineticPreRenderFn_ = null;
+
+ /**
+ * @type {ol.Pixel}
+ */
+ this.lastCentroid = null;
+
+};
+goog.inherits(ol.interaction.TouchPan, ol.interaction.Touch);
+
+
+/**
+ * @inheritDoc
+ */
+ol.interaction.TouchPan.prototype.handleTouchMove = function(mapBrowserEvent) {
+ goog.asserts.assert(this.targetTouches.length >= 1);
+ var centroid = ol.interaction.Touch.centroid(this.targetTouches);
+ if (!goog.isNull(this.lastCentroid)) {
+ this.kinetic_.update(centroid.x, centroid.y);
+ var deltaX = this.lastCentroid.x - centroid.x;
+ var deltaY = centroid.y - this.lastCentroid.y;
+ var view = mapBrowserEvent.map.getView();
+ var center = new ol.Coordinate(deltaX, deltaY)
+ .scale(view.getResolution())
+ .rotate(view.getRotation())
+ .add(view.getCenter());
+ view.setCenter(center);
+ }
+ this.lastCentroid = centroid;
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.interaction.TouchPan.prototype.handleTouchEnd =
+ function(mapBrowserEvent) {
+ var map = mapBrowserEvent.map;
+ var view = map.getView();
+ if (this.targetTouches.length == 0) {
+ view.setHint(ol.ViewHint.PANNING, -1);
+ if (this.kinetic_.end()) {
+ var distance = this.kinetic_.getDistance();
+ var angle = this.kinetic_.getAngle();
+ var center = view.getCenter();
+ this.kineticPreRenderFn_ = this.kinetic_.pan(center);
+ map.addPreRenderFunction(this.kineticPreRenderFn_);
+ var centerpx = map.getPixelFromCoordinate(center);
+ var destpx = new ol.Pixel(
+ centerpx.x - distance * Math.cos(angle),
+ centerpx.y - distance * Math.sin(angle));
+ var dest = map.getCoordinateFromPixel(destpx);
+ view.setCenter(dest);
+ }
+ return false;
+ } else {
+ return true;
+ }
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.interaction.TouchPan.prototype.handleTouchStart =
+ function(mapBrowserEvent) {
+ if (this.targetTouches.length >= 1) {
+ var map = mapBrowserEvent.map;
+ var view = map.getView();
+ this.lastCentroid = null;
+ if (!goog.isNull(this.kineticPreRenderFn_) &&
+ map.removePreRenderFunction(this.kineticPreRenderFn_)) {
+ map.requestRenderFrame();
+ view.setCenter(mapBrowserEvent.frameState.view2DState.center);
+ this.kineticPreRenderFn_ = null;
+ }
+ this.kinetic_.begin();
+ view.setHint(ol.ViewHint.PANNING, 1);
+ return true;
+ } else {
+ return false;
+ }
+};
diff --git a/src/ol/interaction/touchrotateandzoominteraction.js b/src/ol/interaction/touchrotateandzoominteraction.js
new file mode 100644
index 0000000000..d06d6ee93d
--- /dev/null
+++ b/src/ol/interaction/touchrotateandzoominteraction.js
@@ -0,0 +1,149 @@
+// FIXME works for View2D only
+
+goog.provide('ol.interaction.TouchRotateAndZoom');
+
+goog.require('goog.asserts');
+goog.require('ol.View');
+goog.require('ol.ViewHint');
+goog.require('ol.interaction.Touch');
+
+
+
+/**
+ * @constructor
+ * @extends {ol.interaction.Touch}
+ */
+ol.interaction.TouchRotateAndZoom = function() {
+
+ goog.base(this);
+
+ /**
+ * @private
+ * @type {number|undefined}
+ */
+ this.lastAngle_;
+
+ /**
+ * @private
+ * @type {number|undefined}
+ */
+ this.lastDistance_;
+
+ /**
+ * @private
+ * @type {boolean}
+ */
+ this.rotating_ = false;
+
+ /**
+ * @private
+ * @type {number}
+ */
+ this.rotationDelta_ = 0.0;
+
+ /**
+ * @private
+ * @type {number}
+ */
+ this.rotationThreshold_ = 0.3;
+
+};
+goog.inherits(ol.interaction.TouchRotateAndZoom, ol.interaction.Touch);
+
+
+/**
+ * @inheritDoc
+ */
+ol.interaction.TouchRotateAndZoom.prototype.handleTouchMove =
+ function(mapBrowserEvent) {
+ goog.asserts.assert(this.targetTouches.length >= 2);
+ var scaleDelta = 1.0;
+ var rotationDelta = 0.0;
+
+ var centroid = ol.interaction.Touch.centroid(this.targetTouches);
+
+ var touch0 = this.targetTouches[0];
+ var touch1 = this.targetTouches[1];
+ var dx = touch0.clientX - touch1.clientX;
+ var dy = touch0.clientY - touch1.clientY;
+
+ // angle between touches
+ var angle = Math.atan2(
+ touch1.clientY - touch0.clientY,
+ touch1.clientX - touch0.clientX);
+
+ // distance between touches
+ var distance = Math.sqrt(dx * dx + dy * dy);
+
+ if (goog.isDef(this.lastDistance_)) {
+ scaleDelta = this.lastDistance_ / distance;
+ }
+ this.lastDistance_ = distance;
+
+ if (goog.isDef(this.lastAngle_)) {
+ var delta = angle - this.lastAngle_;
+ this.rotationDelta_ += delta;
+ if (!this.rotating_ &&
+ Math.abs(this.rotationDelta_) > this.rotationThreshold_) {
+ this.rotating_ = true;
+ }
+ rotationDelta = delta;
+ }
+ this.lastAngle_ = angle;
+
+ var map = mapBrowserEvent.map;
+ var view = map.getView();
+
+ // rotate / scale anchor point.
+ // FIXME: should be the intersection point between the lines:
+ // touch0,touch1 and previousTouch0,previousTouch1
+ var viewportPosition = goog.style.getClientPosition(map.getViewport());
+ centroid.x -= viewportPosition.x;
+ centroid.y -= viewportPosition.y;
+ var anchor = map.getCoordinateFromPixel(centroid);
+
+ // scale, bypass the resolution constraint
+ view.zoom_(map, view.getResolution() * scaleDelta, anchor);
+
+ // rotate
+ if (this.rotating_) {
+ view.rotate(map, view.getRotation() + rotationDelta, anchor);
+ }
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.interaction.TouchRotateAndZoom.prototype.handleTouchEnd =
+ function(mapBrowserEvent) {
+ if (this.targetTouches.length < 2) {
+ var map = mapBrowserEvent.map;
+ var view = map.getView();
+ // take the resolution constraint into account
+ view.zoomToResolution(map, view.getResolution());
+ view.setHint(ol.ViewHint.PANNING, -1);
+ return false;
+ } else {
+ return true;
+ }
+};
+
+
+/**
+ * @inheritDoc
+ */
+ol.interaction.TouchRotateAndZoom.prototype.handleTouchStart =
+ function(mapBrowserEvent) {
+ if (this.targetTouches.length >= 2) {
+ var view = mapBrowserEvent.map.getView();
+ this.lastDistance_ = undefined;
+ this.lastAngle_ = undefined;
+ this.rotating_ = false;
+ this.rotationDelta_ = 0.0;
+ view.setHint(ol.ViewHint.PANNING, 1);
+ return true;
+ } else {
+ return false;
+ }
+};
diff --git a/src/ol/map.js b/src/ol/map.js
index 2c4ceea383..ad1fa4d8c0 100644
--- a/src/ol/map.js
+++ b/src/ol/map.js
@@ -54,6 +54,8 @@ goog.require('ol.interaction.Interaction');
goog.require('ol.interaction.KeyboardPan');
goog.require('ol.interaction.KeyboardZoom');
goog.require('ol.interaction.MouseWheelZoom');
+goog.require('ol.interaction.TouchPan');
+goog.require('ol.interaction.TouchRotateAndZoom');
goog.require('ol.interaction.condition');
goog.require('ol.layer.Layer');
goog.require('ol.renderer.Map');
@@ -959,6 +961,18 @@ ol.Map.createInteractions_ = function(mapOptions) {
interactions.push(new ol.interaction.DblClickZoom(zoomDelta));
}
+ var touchPan = goog.isDef(mapOptions.touchPan) ?
+ mapOptions.touchPan : true;
+ if (touchPan) {
+ interactions.push(new ol.interaction.TouchPan());
+ }
+
+ var touchRotateZoom = goog.isDef(mapOptions.touchRotateZoom) ?
+ mapOptions.touchRotateZoom : true;
+ if (touchRotateZoom) {
+ interactions.push(new ol.interaction.TouchRotateAndZoom());
+ }
+
var dragPan = goog.isDef(mapOptions.dragPan) ?
mapOptions.dragPan : true;
if (dragPan) {
diff --git a/src/ol/mapbrowserevent.js b/src/ol/mapbrowserevent.js
index 079f43b47b..792585eff0 100644
--- a/src/ol/mapbrowserevent.js
+++ b/src/ol/mapbrowserevent.js
@@ -3,7 +3,6 @@ goog.provide('ol.MapBrowserEvent.EventType');
goog.provide('ol.MapBrowserEventHandler');
goog.require('goog.array');
-goog.require('goog.asserts');
goog.require('goog.events.BrowserEvent');
goog.require('goog.events.EventTarget');
goog.require('goog.events.EventType');
@@ -49,6 +48,20 @@ 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,10 +127,10 @@ ol.MapBrowserEventHandler = function(map) {
/**
* Timestamp for the first click of a double click. Will be set back to 0
* as soon as a double click is detected.
- * @type {number}
+ * @type {?number}
* @private
*/
- this.timestamp_ = 0;
+ this.timestamp_ = null;
/**
* @type {?number}
@@ -137,6 +150,12 @@ ol.MapBrowserEventHandler = function(map) {
*/
this.dragListenerKeys_ = null;
+ /**
+ * @type {Array.}
+ * @private
+ */
+ this.touchListenerKeys_ = null;
+
/**
* @type {goog.events.BrowserEvent}
* @private
@@ -144,38 +163,32 @@ ol.MapBrowserEventHandler = function(map) {
this.down_ = null;
var element = this.map_.getViewport();
- if (!ol.BrowserFeature.HAS_TOUCH) {
- this.clickListenerKey_ = goog.events.listen(element,
- [goog.events.EventType.CLICK, goog.events.EventType.DBLCLICK],
- this.click_, false, this);
- }
+ this.clickListenerKey_ = goog.events.listen(element,
+ [goog.events.EventType.CLICK, goog.events.EventType.DBLCLICK],
+ this.click_, false, this);
this.downListenerKey_ = goog.events.listen(element,
- ol.BrowserFeature.HAS_TOUCH ?
- goog.events.EventType.TOUCHSTART :
- goog.events.EventType.MOUSEDOWN,
- this.handleDown_, false, this);
+ goog.events.EventType.MOUSEDOWN,
+ this.handleMouseDown_, false, this);
+ // touch events
+ this.touchListenerKeys_ = [
+ goog.events.listen(element, [
+ goog.events.EventType.TOUCHSTART,
+ ol.MapBrowserEvent.IEEventType.MSPOINTERDOWN
+ ], this.handleTouchStart_, false, this),
+ goog.events.listen(element, [
+ goog.events.EventType.TOUCHMOVE,
+ ol.MapBrowserEvent.IEEventType.MSPOINTERMOVE
+ ], this.handleTouchMove_, false, this),
+ goog.events.listen(element, [
+ goog.events.EventType.TOUCHEND,
+ ol.MapBrowserEvent.IEEventType.MSPOINTERUP
+ ], this.handleTouchEnd_, false, this)
+ ];
+
};
goog.inherits(ol.MapBrowserEventHandler, goog.events.EventTarget);
-/**
- * @param {goog.events.BrowserEvent} browserEvent Browser event.
- * @private
- */
-ol.MapBrowserEventHandler.prototype.touchEnableBrowserEvent_ =
- function(browserEvent) {
- if (ol.BrowserFeature.HAS_TOUCH) {
- goog.asserts.assert(browserEvent instanceof goog.events.BrowserEvent);
- var nativeEvent = browserEvent.getBrowserEvent();
- if (nativeEvent.touches && nativeEvent.touches.length) {
- var nativeTouch = nativeEvent.touches[0];
- browserEvent.clientX = nativeTouch.clientX;
- browserEvent.clientY = nativeTouch.clientY;
- }
- }
-};
-
-
/**
* @param {goog.events.BrowserEvent} browserEvent Browser event.
* @private
@@ -183,15 +196,15 @@ ol.MapBrowserEventHandler.prototype.touchEnableBrowserEvent_ =
ol.MapBrowserEventHandler.prototype.click_ = function(browserEvent) {
if (!this.dragged_) {
var newEvent;
- if (browserEvent.type !== goog.events.EventType.DBLCLICK) {
- newEvent = new ol.MapBrowserEvent(
- ol.MapBrowserEvent.EventType.CLICK, this.map_, browserEvent);
- this.dispatchEvent(newEvent);
- }
- if (!this.timestamp_) {
+ var type = browserEvent.type;
+ if (this.timestamp_ == 0 || type == goog.events.EventType.DBLCLICK) {
newEvent = new ol.MapBrowserEvent(
ol.MapBrowserEvent.EventType.DBLCLICK, this.map_, browserEvent);
this.dispatchEvent(newEvent);
+ } else if (type == goog.events.EventType.CLICK) {
+ newEvent = new ol.MapBrowserEvent(
+ ol.MapBrowserEvent.EventType.CLICK, this.map_, browserEvent);
+ this.dispatchEvent(newEvent);
}
}
};
@@ -201,19 +214,8 @@ ol.MapBrowserEventHandler.prototype.click_ = function(browserEvent) {
* @param {goog.events.BrowserEvent} browserEvent Browser event.
* @private
*/
-ol.MapBrowserEventHandler.prototype.handleUp_ = function(browserEvent) {
+ol.MapBrowserEventHandler.prototype.handleMouseUp_ = function(browserEvent) {
if (this.previous_) {
- if (!this.dragged_) {
- var now = new Date().getTime();
- if (!this.timestamp_ || now - this.timestamp_ > 250) {
- this.timestamp_ = now;
- } else {
- this.timestamp_ = 0;
- }
- if (ol.BrowserFeature.HAS_TOUCH) {
- this.click_(this.down_);
- }
- }
this.down_ = null;
goog.array.forEach(this.dragListenerKeys_, goog.events.unlistenByKey);
this.dragListenerKeys_ = null;
@@ -231,12 +233,11 @@ ol.MapBrowserEventHandler.prototype.handleUp_ = function(browserEvent) {
* @param {goog.events.BrowserEvent} browserEvent Browser event.
* @private
*/
-ol.MapBrowserEventHandler.prototype.handleDown_ = function(browserEvent) {
+ol.MapBrowserEventHandler.prototype.handleMouseDown_ = function(browserEvent) {
var newEvent = new ol.MapBrowserEvent(
ol.MapBrowserEvent.EventType.DOWN, this.map_, browserEvent);
this.dispatchEvent(newEvent);
if (!this.previous_) {
- this.touchEnableBrowserEvent_(browserEvent);
this.down_ = browserEvent;
this.previous_ = {
clientX: browserEvent.clientX,
@@ -244,21 +245,13 @@ ol.MapBrowserEventHandler.prototype.handleDown_ = function(browserEvent) {
};
this.dragged_ = false;
this.dragListenerKeys_ = [
- goog.events.listen(document,
- ol.BrowserFeature.HAS_TOUCH ?
- goog.events.EventType.TOUCHMOVE :
- goog.events.EventType.MOUSEMOVE,
- this.drag_, false, this),
- goog.events.listen(document,
- ol.BrowserFeature.HAS_TOUCH ?
- goog.events.EventType.TOUCHEND :
- goog.events.EventType.MOUSEUP,
- this.handleUp_, false, this)
+ goog.events.listen(document, goog.events.EventType.MOUSEMOVE,
+ this.handleMouseMove_, false, this),
+ goog.events.listen(document, goog.events.EventType.MOUSEUP,
+ this.handleMouseUp_, false, this)
];
- if (browserEvent.type === goog.events.EventType.MOUSEDOWN) {
- // prevent browser image dragging on pointer devices
- browserEvent.preventDefault();
- }
+ // prevent browser image dragging with the dom renderer
+ browserEvent.preventDefault();
}
};
@@ -267,7 +260,7 @@ ol.MapBrowserEventHandler.prototype.handleDown_ = function(browserEvent) {
* @param {goog.events.BrowserEvent} browserEvent Browser event.
* @private
*/
-ol.MapBrowserEventHandler.prototype.drag_ = function(browserEvent) {
+ol.MapBrowserEventHandler.prototype.handleMouseMove_ = function(browserEvent) {
var newEvent;
if (!this.dragged_) {
this.dragged_ = true;
@@ -275,19 +268,64 @@ ol.MapBrowserEventHandler.prototype.drag_ = function(browserEvent) {
ol.MapBrowserEvent.EventType.DRAGSTART, this.map_, this.down_);
this.dispatchEvent(newEvent);
}
- this.touchEnableBrowserEvent_(browserEvent);
this.previous_ = {
clientX: browserEvent.clientX,
clientY: browserEvent.clientY
};
- // prevent viewport dragging on touch devices
- browserEvent.preventDefault();
newEvent = new ol.MapBrowserEvent(
ol.MapBrowserEvent.EventType.DRAG, this.map_, browserEvent);
this.dispatchEvent(newEvent);
};
+/**
+ * @param {goog.events.BrowserEvent} browserEvent Browser event.
+ * @private
+ */
+ol.MapBrowserEventHandler.prototype.handleTouchStart_ = function(browserEvent) {
+ // prevent context menu
+ browserEvent.preventDefault();
+ this.down_ = browserEvent;
+ this.dragged_ = false;
+ var newEvent = new ol.MapBrowserEvent(
+ ol.MapBrowserEvent.EventType.TOUCHSTART, this.map_, browserEvent);
+ this.dispatchEvent(newEvent);
+};
+
+
+/**
+ * @param {goog.events.BrowserEvent} browserEvent Browser event.
+ * @private
+ */
+ol.MapBrowserEventHandler.prototype.handleTouchMove_ = function(browserEvent) {
+ this.dragged_ = true;
+ var newEvent = new ol.MapBrowserEvent(
+ ol.MapBrowserEvent.EventType.TOUCHMOVE, this.map_, browserEvent);
+ this.dispatchEvent(newEvent);
+};
+
+
+/**
+ * @param {goog.events.BrowserEvent} browserEvent Browser event.
+ * @private
+ */
+ol.MapBrowserEventHandler.prototype.handleTouchEnd_ = function(browserEvent) {
+ var newEvent = new ol.MapBrowserEvent(
+ ol.MapBrowserEvent.EventType.TOUCHEND, this.map_, browserEvent);
+ this.dispatchEvent(newEvent);
+ if (!this.dragged_) {
+ var now = goog.now();
+ if (!this.timestamp_ || now - this.timestamp_ > 250) {
+ this.timestamp_ = now;
+ } else {
+ this.timestamp_ = 0;
+ }
+ this.click_(this.down_);
+ }
+ this.down_ = null;
+};
+
+
/**
* FIXME empty description for jsdoc
*/
@@ -298,6 +336,10 @@ ol.MapBrowserEventHandler.prototype.disposeInternal = function() {
goog.array.forEach(this.dragListenerKeys_, goog.events.unlistenByKey);
this.dragListenerKeys_ = null;
}
+ if (!goog.isNull(this.touchListenerKeys_)) {
+ goog.array.forEach(this.touchListenerKeys_, goog.events.unlistenByKey);
+ this.touchListenerKeys_ = null;
+ }
goog.base(this, 'disposeInternal');
};
@@ -309,8 +351,11 @@ ol.MapBrowserEventHandler.prototype.disposeInternal = function() {
ol.MapBrowserEvent.EventType = {
CLICK: goog.events.EventType.CLICK,
DBLCLICK: goog.events.EventType.DBLCLICK,
+ DOWN: 'down',
DRAGSTART: 'dragstart',
DRAG: 'drag',
DRAGEND: 'dragend',
- DOWN: 'down'
+ TOUCHSTART: goog.events.EventType.TOUCHSTART,
+ TOUCHMOVE: goog.events.EventType.TOUCHMOVE,
+ TOUCHEND: goog.events.EventType.TOUCHEND
};
diff --git a/src/ol/projection.js b/src/ol/projection.js
index d6c57812a0..3e1692d01c 100644
--- a/src/ol/projection.js
+++ b/src/ol/projection.js
@@ -254,7 +254,6 @@ ol.Projection.createProjection = function(projection, defaultCode) {
* @param {ol.TransformFunction} transformFn Transform.
*/
ol.Projection.addTransform = function(source, destination, transformFn) {
- var projections = ol.Projection.projections_;
var sourceCode = source.getCode();
var destinationCode = destination.getCode();
var transforms = ol.Projection.transforms_;
@@ -267,6 +266,31 @@ ol.Projection.addTransform = function(source, destination, transformFn) {
};
+/**
+ * Unregisters the conversion function to convert coordinates from the source
+ * projection to the destination projection. This method is used to clean up
+ * cached transforms during testing.
+ *
+ * @param {ol.Projection} source Source projection.
+ * @param {ol.Projection} destination Destination projection.
+ * @return {ol.TransformFunction} transformFn The unregistered transform.
+ */
+ol.Projection.removeTransform = function(source, destination) {
+ var sourceCode = source.getCode();
+ var destinationCode = destination.getCode();
+ var transforms = ol.Projection.transforms_;
+ goog.asserts.assert(sourceCode in transforms);
+ goog.asserts.assert(destinationCode in transforms[sourceCode]);
+ var transform = transforms[sourceCode][destinationCode];
+ delete transforms[sourceCode][destinationCode];
+ var keys = goog.object.getKeys(transforms[sourceCode]);
+ if (keys.length == 0) {
+ delete transforms[sourceCode];
+ }
+ return transform;
+};
+
+
/**
* @param {string} code Code which is a combination of authority and identifier
* such as “EPSG:4326”.
@@ -354,7 +378,7 @@ ol.Projection.getTransform = function(source, destination) {
proj4jsDestination = destination;
} else {
proj4jsDestination =
- ol.Projection.getProj4jsProjectionFromCode_(source.getCode());
+ ol.Projection.getProj4jsProjectionFromCode_(destination.getCode());
}
var destinationProj4jsProj = proj4jsDestination.getProj4jsProj();
transform =
diff --git a/src/ol/renderer/canvas/canvastilelayerrenderer.js b/src/ol/renderer/canvas/canvastilelayerrenderer.js
index e7c48f044c..8204edcf33 100644
--- a/src/ol/renderer/canvas/canvastilelayerrenderer.js
+++ b/src/ol/renderer/canvas/canvastilelayerrenderer.js
@@ -129,9 +129,9 @@ ol.renderer.canvas.TileLayer.prototype.renderFrame =
var tilesToDrawByZ = {};
tilesToDrawByZ[z] = {};
- function isLoaded(tile) {
+ var isLoaded = function(tile) {
return !goog.isNull(tile) && tile.getState() == ol.TileState.LOADED;
- }
+ };
var findLoadedTiles = goog.bind(tileSource.findLoadedTiles, tileSource,
tilesToDrawByZ, isLoaded);
@@ -199,6 +199,7 @@ ol.renderer.canvas.TileLayer.prototype.renderFrame =
}
this.updateUsedTiles(frameState.usedTiles, tileSource, z, tileRange);
+ tileSource.useLowResolutionTiles(z, frameState.extent);
this.scheduleExpireCache(frameState, tileSource);
var transform = this.transform_;
diff --git a/src/ol/renderer/dom/domtilelayerrenderer.js b/src/ol/renderer/dom/domtilelayerrenderer.js
index faeb67d47d..9b5dd26b32 100644
--- a/src/ol/renderer/dom/domtilelayerrenderer.js
+++ b/src/ol/renderer/dom/domtilelayerrenderer.js
@@ -93,9 +93,9 @@ ol.renderer.dom.TileLayer.prototype.renderFrame =
var tilesToDrawByZ = {};
tilesToDrawByZ[z] = {};
- function isLoaded(tile) {
+ var isLoaded = function(tile) {
return !goog.isNull(tile) && tile.getState() == ol.TileState.LOADED;
- }
+ };
var findLoadedTiles = goog.bind(tileSource.findLoadedTiles, tileSource,
tilesToDrawByZ, isLoaded);
@@ -217,6 +217,7 @@ ol.renderer.dom.TileLayer.prototype.renderFrame =
}
this.updateUsedTiles(frameState.usedTiles, tileSource, z, tileRange);
+ tileSource.useLowResolutionTiles(z, frameState.extent);
this.scheduleExpireCache(frameState, tileSource);
};
diff --git a/src/ol/renderer/layerrenderer.js b/src/ol/renderer/layerrenderer.js
index 3379e0da5e..f1477ac8d7 100644
--- a/src/ol/renderer/layerrenderer.js
+++ b/src/ol/renderer/layerrenderer.js
@@ -14,7 +14,6 @@ goog.require('ol.TileState');
goog.require('ol.layer.Layer');
goog.require('ol.layer.LayerProperty');
goog.require('ol.layer.LayerState');
-goog.require('ol.source.Source');
goog.require('ol.source.TileSource');
@@ -222,24 +221,24 @@ ol.renderer.Layer.prototype.updateAttributions =
/**
* @protected
* @param {Object.>} usedTiles Used tiles.
- * @param {ol.source.Source} source Source.
+ * @param {ol.source.TileSource} tileSource Tile source.
* @param {number} z Z.
* @param {ol.TileRange} tileRange Tile range.
*/
ol.renderer.Layer.prototype.updateUsedTiles =
- function(usedTiles, source, z, tileRange) {
+ function(usedTiles, tileSource, z, tileRange) {
// FIXME should we use tilesToDrawByZ instead?
- var sourceKey = goog.getUid(source).toString();
+ var tileSourceKey = goog.getUid(tileSource).toString();
var zKey = z.toString();
- if (sourceKey in usedTiles) {
- if (zKey in usedTiles[sourceKey]) {
- usedTiles[sourceKey][zKey].extend(tileRange);
+ if (tileSourceKey in usedTiles) {
+ if (zKey in usedTiles[tileSourceKey]) {
+ usedTiles[tileSourceKey][zKey].extend(tileRange);
} else {
- usedTiles[sourceKey][zKey] = tileRange;
+ usedTiles[tileSourceKey][zKey] = tileRange;
}
} else {
- usedTiles[sourceKey] = {};
- usedTiles[sourceKey][zKey] = tileRange;
+ usedTiles[tileSourceKey] = {};
+ usedTiles[tileSourceKey][zKey] = tileRange;
}
};
@@ -247,15 +246,15 @@ ol.renderer.Layer.prototype.updateUsedTiles =
/**
* @protected
* @param {Object.>} wantedTiles Wanted tiles.
- * @param {ol.source.Source} source Source.
+ * @param {ol.source.TileSource} tileSource Tile source.
* @param {ol.TileCoord} tileCoord Tile coordinate.
*/
ol.renderer.Layer.prototype.updateWantedTiles =
- function(wantedTiles, source, tileCoord) {
- var sourceKey = goog.getUid(source).toString();
+ function(wantedTiles, tileSource, tileCoord) {
+ var tileSourceKey = goog.getUid(tileSource).toString();
var coordKey = tileCoord.toString();
- if (!(sourceKey in wantedTiles)) {
- wantedTiles[sourceKey] = {};
+ if (!(tileSourceKey in wantedTiles)) {
+ wantedTiles[tileSourceKey] = {};
}
- wantedTiles[sourceKey][coordKey] = true;
+ wantedTiles[tileSourceKey][coordKey] = true;
};
diff --git a/src/ol/renderer/webgl/webgltilelayerrenderer.js b/src/ol/renderer/webgl/webgltilelayerrenderer.js
index 53405ca10a..9b75e0d0b1 100644
--- a/src/ol/renderer/webgl/webgltilelayerrenderer.js
+++ b/src/ol/renderer/webgl/webgltilelayerrenderer.js
@@ -365,10 +365,10 @@ ol.renderer.webgl.TileLayer.prototype.renderFrame =
var tilesToDrawByZ = {};
tilesToDrawByZ[z] = {};
- function isLoaded(tile) {
+ var isLoaded = function(tile) {
return !goog.isNull(tile) && tile.getState() == ol.TileState.LOADED &&
mapRenderer.isTileTextureLoaded(tile);
- }
+ };
var findLoadedTiles = goog.bind(tileSource.findLoadedTiles, tileSource,
tilesToDrawByZ, isLoaded);
@@ -459,6 +459,7 @@ ol.renderer.webgl.TileLayer.prototype.renderFrame =
}
this.updateUsedTiles(frameState.usedTiles, tileSource, z, tileRange);
+ tileSource.useLowResolutionTiles(z, frameState.extent);
this.scheduleExpireCache(frameState, tileSource);
goog.vec.Mat4.makeIdentity(this.texCoordMatrix_);
diff --git a/src/ol/source/imagetilesource.js b/src/ol/source/imagetilesource.js
index 4a59b1bcff..d47b9215e5 100644
--- a/src/ol/source/imagetilesource.js
+++ b/src/ol/source/imagetilesource.js
@@ -109,3 +109,14 @@ ol.source.ImageTileSource.prototype.getTile = function(tileCoord) {
ol.source.ImageTileSource.prototype.getTileCoordUrl = function(tileCoord) {
return this.tileUrlFunction(tileCoord);
};
+
+
+/**
+ * @inheritDoc
+ */
+ol.source.ImageTileSource.prototype.useTile = function(tileCoord) {
+ var key = tileCoord.toString();
+ if (this.tileCache_.containsKey(key)) {
+ this.tileCache_.get(key);
+ }
+};
diff --git a/src/ol/source/singleimagewmssource.js b/src/ol/source/singleimagewmssource.js
index 3529678443..84e66db61f 100644
--- a/src/ol/source/singleimagewmssource.js
+++ b/src/ol/source/singleimagewmssource.js
@@ -1,5 +1,6 @@
goog.provide('ol.source.SingleImageWMS');
+goog.require('goog.uri.utils');
goog.require('ol.Extent');
goog.require('ol.Image');
goog.require('ol.ImageUrlFunction');
diff --git a/src/ol/source/tiledwmssource.js b/src/ol/source/tiledwmssource.js
index b09147cf2c..a1093f21e4 100644
--- a/src/ol/source/tiledwmssource.js
+++ b/src/ol/source/tiledwmssource.js
@@ -69,7 +69,7 @@ ol.source.TiledWMS = function(tiledWMSOptions) {
tileUrlFunction = ol.TileUrlFunction.nullTileUrlFunction;
}
- function tileCoordTransform(tileCoord) {
+ var tileCoordTransform = function(tileCoord) {
if (tileGrid.getResolutions().length <= tileCoord.z) {
return null;
}
@@ -90,7 +90,7 @@ ol.source.TiledWMS = function(tiledWMSOptions) {
return null;
}
return new ol.TileCoord(tileCoord.z, x, tileCoord.y);
- }
+ };
goog.base(this, {
attributions: tiledWMSOptions.attributions,
diff --git a/src/ol/source/tilesource.js b/src/ol/source/tilesource.js
index e9666dada6..c250951e7e 100644
--- a/src/ol/source/tilesource.js
+++ b/src/ol/source/tilesource.js
@@ -119,3 +119,29 @@ ol.source.TileSource.prototype.getTile = goog.abstractMethod;
ol.source.TileSource.prototype.getTileGrid = function() {
return this.tileGrid;
};
+
+
+/**
+ * @param {number} z Z.
+ * @param {ol.Extent} extent Extent.
+ */
+ol.source.TileSource.prototype.useLowResolutionTiles = function(z, extent) {
+ var tileGrid = this.getTileGrid();
+ var tileRange, x, y, zKey;
+ // FIXME this should loop up to tileGrid's minZ when implemented
+ for (; z >= 0; --z) {
+ tileRange = tileGrid.getTileRangeForExtentAndZ(extent, z);
+ for (x = tileRange.minX; x <= tileRange.maxX; ++x) {
+ for (y = tileRange.minY; y <= tileRange.maxY; ++y) {
+ this.useTile(z + '/' + x + '/' + y);
+ }
+ }
+ }
+};
+
+
+/**
+ * Marks a tile coord as being used, without triggering a load.
+ * @param {string} tileCoordKey Tile coordinate key.
+ */
+ol.source.TileSource.prototype.useTile = goog.nullFunction;
diff --git a/test/spec/ol/map.test.js b/test/spec/ol/map.test.js
index e859e7e8e8..db5ed7f546 100644
--- a/test/spec/ol/map.test.js
+++ b/test/spec/ol/map.test.js
@@ -77,7 +77,9 @@ describe('ol.Map', function() {
dragPan: false,
keyboard: false,
mouseWheelZoom: false,
- shiftDragZoom: false
+ shiftDragZoom: false,
+ touchPan: false,
+ touchRotateZoom: false
};
});
diff --git a/test/spec/ol/projection.test.js b/test/spec/ol/projection.test.js
index eb1c9b4787..1ee2c4d91c 100644
--- a/test/spec/ol/projection.test.js
+++ b/test/spec/ol/projection.test.js
@@ -2,6 +2,27 @@ goog.provide('ol.test.Projection');
describe('ol.Projection', function() {
+ beforeEach(function() {
+ spyOn(ol.Projection, 'addTransform').andCallThrough();
+ });
+
+ afterEach(function() {
+ var argsForCall = ol.Projection.addTransform.argsForCall;
+ for (var i = 0, ii = argsForCall.length; i < ii; ++i) {
+ try {
+ ol.Projection.removeTransform.apply(
+ ol.Projection, argsForCall[i].splice(0, 2));
+ } catch (error) {
+ if (error instanceof goog.asserts.AssertionError) {
+ // The removeTransform function may have been called explicitly by the
+ // tests, so we pass.
+ } else {
+ throw error;
+ }
+ }
+ }
+ });
+
describe('projection equivalence', function() {
function _testAllEquivalent(codes) {
@@ -23,14 +44,13 @@ describe('ol.Projection', function() {
});
it('gives that CRS:84, urn:ogc:def:crs:EPSG:6.6:4326, EPSG:4326 are ' +
- 'equivalent', function() {
- _testAllEquivalent([
- 'CRS:84',
- 'urn:ogc:def:crs:EPSG:6.6:4326',
- 'EPSG:4326'
- ]);
- });
-
+ 'equivalent', function() {
+ _testAllEquivalent([
+ 'CRS:84',
+ 'urn:ogc:def:crs:EPSG:6.6:4326',
+ 'EPSG:4326'
+ ]);
+ });
});
describe('identify transform', function() {
@@ -126,8 +146,72 @@ describe('ol.Projection', function() {
});
+ describe('ol.Projection.getTransform()', function() {
+
+ var sm = ol.Projection.getFromCode('GOOGLE');
+ var gg = ol.Projection.getFromCode('EPSG:4326');
+
+ it('returns a transform function', function() {
+ var transform = ol.Projection.getTransform(sm, gg);
+ expect(typeof transform).toBe('function');
+
+ var coordinate = transform(new ol.Coordinate(-12000000, 5000000));
+
+ expect(coordinate.x).toRoughlyEqual(-107.79783409434258, 1e-9);
+ expect(coordinate.y).toRoughlyEqual(40.91627447067577, 1e-9);
+ });
+
+ });
+
+
+ describe('ol.Projection.getTransformFromCodes()', function() {
+
+ it('returns a function', function() {
+ var transform = ol.Projection.getTransformFromCodes(
+ 'GOOGLE', 'EPSG:4326');
+ expect(typeof transform).toBe('function');
+ });
+
+ it('returns a transform function', function() {
+ var transform = ol.Projection.getTransformFromCodes(
+ 'GOOGLE', 'EPSG:4326');
+ expect(typeof transform).toBe('function');
+
+ var coordinate = transform(
+ new ol.Coordinate(-626172.13571216376, 6887893.4928337997));
+
+ expect(coordinate.x).toRoughlyEqual(-5.625, 1e-9);
+ expect(coordinate.y).toRoughlyEqual(52.4827802220782, 1e-9);
+
+ });
+
+ });
+
+ describe('ol.Projection.removeTransform()', function() {
+
+ var extent = new ol.Extent(-180, -90, 180, 90);
+ var units = ol.ProjectionUnits.DEGREES;
+
+ it('removes functions cached by addTransform', function() {
+ var foo = new ol.Projection('foo', units, extent);
+ var bar = new ol.Projection('bar', units, extent);
+ var transform = function() {};
+ ol.Projection.addTransform(foo, bar, transform);
+ expect(ol.Projection.transforms_).not.toBeUndefined();
+ expect(ol.Projection.transforms_.foo).not.toBeUndefined();
+ expect(ol.Projection.transforms_.foo.bar).toBe(transform);
+
+ var removed = ol.Projection.removeTransform(foo, bar);
+ expect(removed).toBe(transform);
+ expect(ol.Projection.transforms_.foo).toBeUndefined();
+ });
+
+ });
+
});
goog.require('goog.array');
goog.require('ol.Coordinate');
+goog.require('ol.Extent');
goog.require('ol.Projection');
+goog.require('ol.ProjectionUnits');