Merge branch 'master' into event
Conflicts: src/ol/Map.js src/ol/event/Drag.js
This commit is contained in:
@@ -1,36 +1,7 @@
|
||||
/**
|
||||
Adds the plovr generated script to the document. The following default
|
||||
values may be overridden with query string parameters:
|
||||
|
||||
* hostname - localhost
|
||||
* port - 9810
|
||||
* mode - SIMPLE
|
||||
* id - ol
|
||||
Adds the plovr generated script to the document.
|
||||
*/
|
||||
(function() {
|
||||
var search = window.location.search.substring(1);
|
||||
var params = {
|
||||
hostname: "localhost",
|
||||
port: "9810",
|
||||
mode: "SIMPLE",
|
||||
id: "ol"
|
||||
};
|
||||
var chunks = search.split("&");
|
||||
var pair;
|
||||
for (var i=chunks.length-1; i>=0; --i) {
|
||||
pair = chunks[i].split("=");
|
||||
params[decodeURIComponent(pair[0])] = decodeURIComponent(pair[1]);
|
||||
}
|
||||
|
||||
var host = params.hostname + ":" + params.port;
|
||||
delete params.hostname;
|
||||
delete params.port;
|
||||
|
||||
var pairs = [];
|
||||
for (var key in params) {
|
||||
pairs.push(encodeURIComponent(key) + "=" + encodeURIComponent(params[key]));
|
||||
}
|
||||
|
||||
var url = "http://" + host + "/compile?" + pairs.join("&");
|
||||
var url = "http://" + window.location.hostname + ":9810/compile?id=ol";
|
||||
document.write("<script type='text/javascript' src='" + url + "'></script>");
|
||||
})();
|
||||
|
||||
@@ -90,6 +90,12 @@ ol.Map = function() {
|
||||
* @type {Element}
|
||||
*/
|
||||
this.viewport_ = null;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {goog.math.Size}
|
||||
*/
|
||||
this.viewportSize_ = null;
|
||||
|
||||
/**
|
||||
* @private
|
||||
@@ -266,34 +272,60 @@ ol.Map.prototype.getResolutionForZoom = function(zoom) {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @return {number} the resolution for the map at the given zoom level
|
||||
*/
|
||||
ol.Map.prototype.getResolution = function() {
|
||||
goog.asserts.assert(goog.isDef(this.renderer_));
|
||||
return this.renderer_.getResolution();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* TODO: We'll have to ask the map overlay renderer for this. This method will
|
||||
* not work once map space is not aligned with pixel space.
|
||||
*
|
||||
* @param {goog.math.Coordinate|{x: number, y: number}} pixel
|
||||
* @return {ol.Loc}
|
||||
*/
|
||||
ol.Map.prototype.getLocForPixel = function(pixel) {
|
||||
return goog.isDef(this.renderer_) ?
|
||||
this.renderer_.getLocForPixel(pixel) : null;
|
||||
ol.Map.prototype.getLocForViewportPixel = function(pixel) {
|
||||
var size = this.getViewportSize();
|
||||
var center = this.center_;
|
||||
var resolution = this.getResolution();
|
||||
var x = center.getX() + (resolution * (pixel.x - (size.width / 2)));
|
||||
var y = center.getY() - (resolution * (pixel.y - (size.height / 2)));
|
||||
return new ol.Loc(x, y, undefined, this.getProjection());
|
||||
};
|
||||
|
||||
/**
|
||||
* TODO: We'll have to ask the map overlay renderer for this. This method will
|
||||
* not work once map space is not aligned with pixel space.
|
||||
*
|
||||
* @param {ol.Loc} loc
|
||||
* @return {{x: number, y: number}}
|
||||
*/
|
||||
ol.Map.prototype.getPixelForLoc = function(loc) {
|
||||
return goog.isDef(this.renderer_) ?
|
||||
this.renderer_.getPixelForLoc(loc) : null;
|
||||
ol.Map.prototype.getViewportPixelForLoc = function(loc) {
|
||||
var size = this.getViewportSize();
|
||||
var center = this.center_;
|
||||
var resolution = this.getResolution();
|
||||
return {
|
||||
x: ((loc.getX() - center.getX()) / resolution) + (size.width / 2),
|
||||
y: ((center.getY() - loc.getY()) / resolution) + (size.height / 2)
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* @return {goog.math.Size} The currently rendered map size in pixels.
|
||||
* @return {goog.math.Size}
|
||||
*/
|
||||
ol.Map.prototype.getSize = function() {
|
||||
//TODO consider caching this when we have something like updateSize
|
||||
return goog.isDef(this.renderer_) ? this.renderer_.getSize() : null;
|
||||
ol.Map.prototype.getViewportSize = function() {
|
||||
// TODO: listen for resize and set this.viewportSize_ null
|
||||
// https://github.com/openlayers/ol3/issues/2
|
||||
if (goog.isNull(this.viewportSize_)) {
|
||||
this.viewportSize_ = goog.style.getSize(this.viewport_);
|
||||
}
|
||||
return this.viewportSize_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {ol.Loc} center Center in map projection.
|
||||
*/
|
||||
@@ -329,8 +361,8 @@ ol.Map.prototype.setZoom = function(zoom, opt_anchor) {
|
||||
return;
|
||||
}
|
||||
if (goog.isDef(opt_anchor)) {
|
||||
var size = this.getSize(),
|
||||
anchorLoc = this.getLocForPixel(opt_anchor),
|
||||
var size = this.getViewportSize(),
|
||||
anchorLoc = this.getLocForViewportPixel(opt_anchor),
|
||||
newRes = this.getResolutionForZoom(newZoom);
|
||||
newCenter = anchorLoc.add(
|
||||
(size.width/2 - opt_anchor.x) * newRes,
|
||||
@@ -491,7 +523,7 @@ ol.Map.prototype.createRenderer = function() {
|
||||
this.mapOverlay_ = goog.dom.createDom('div', 'ol-overlay-map');
|
||||
this.staticOverlay_ = goog.dom.createDom('div', {
|
||||
'class': staticCls,
|
||||
'style': 'width:100%;height:100%;top:0;left:0;position:absolute'
|
||||
'style': 'width:100%;height:100%;top:0;left:0;position:absolute;z-index:1'
|
||||
});
|
||||
}
|
||||
if (!goog.isNull(viewport)) {
|
||||
@@ -500,10 +532,13 @@ ol.Map.prototype.createRenderer = function() {
|
||||
};
|
||||
|
||||
/**
|
||||
* TODO: This method will need to be reworked/revisited when renderers can
|
||||
* display a map that is rotated or otherwise not aligned with pixel space.
|
||||
*
|
||||
* @param {number} dx pixels to move in x direction
|
||||
* @param {number} dy pixels to move in x direction
|
||||
*/
|
||||
ol.Map.prototype.moveByPx = function(dx, dy) {
|
||||
ol.Map.prototype.moveByViewportPx = function(dx, dy) {
|
||||
if (!goog.isNull(this.center_) && goog.isDef(this.zoom_)) {
|
||||
var resolution = this.getResolutionForZoom(this.zoom_),
|
||||
center = new ol.Loc(
|
||||
|
||||
@@ -243,7 +243,7 @@ ol.Popup.prototype.setAnchorOffset_ = function() {
|
||||
this.pos_ = new ol.geom.Point(this.anchor_.getX(), this.anchor_.getY());
|
||||
}
|
||||
var pos = /** @type {ol.Loc} */ (this.pos_);
|
||||
var popupPosPx = this.map_.getPixelForLoc(pos);
|
||||
var popupPosPx = this.map_.getViewportPixelForLoc(pos);
|
||||
var popupSize = goog.style.getSize(this.container_);
|
||||
|
||||
switch(this.placement_) {
|
||||
|
||||
@@ -43,9 +43,7 @@ ol.control.Attribution.prototype.setMap = function(map) {
|
||||
var staticOverlay = map.getStaticOverlay();
|
||||
if (goog.isNull(this.container_)) {
|
||||
this.container_ = goog.dom.createDom('div', this.CLS);
|
||||
// This is not registered as priority listener, so priority listeners
|
||||
// can still get the click event.
|
||||
map.getEvents().register('click', this.stopLinkClick, this);
|
||||
goog.events.listen(this.container_, 'click', ol.event.stopPropagation);
|
||||
}
|
||||
if (!goog.isNull(staticOverlay)) {
|
||||
goog.dom.append(staticOverlay, this.container_);
|
||||
@@ -53,16 +51,6 @@ ol.control.Attribution.prototype.setMap = function(map) {
|
||||
goog.base(this, 'setMap', map);
|
||||
};
|
||||
|
||||
/**
|
||||
* Prevent clicks on links in the attribution from getting through to
|
||||
* listeners.
|
||||
*/
|
||||
ol.control.Attribution.prototype.stopLinkClick = function(evt) {
|
||||
var node = evt.target;
|
||||
return node.nodeName !== 'A' ||
|
||||
!goog.dom.getAncestorByClass(node, this.CLS);
|
||||
};
|
||||
|
||||
/** @inheritDoc */
|
||||
ol.control.Attribution.prototype.activate = function() {
|
||||
var active = goog.base(this, 'activate');
|
||||
@@ -96,6 +84,7 @@ ol.control.Attribution.prototype.update = function() {
|
||||
};
|
||||
|
||||
ol.control.Attribution.prototype.destroy = function() {
|
||||
goog.events.unlisten(this.container_, 'click', ol.event.stopPropagation);
|
||||
goog.dom.removeNode(this.container_);
|
||||
goog.base(this, 'destroy');
|
||||
};
|
||||
|
||||
@@ -20,6 +20,12 @@ ol.control.Navigation = function(opt_autoActivate) {
|
||||
this.autoActivate_ =
|
||||
goog.isDef(opt_autoActivate) ? opt_autoActivate : true;
|
||||
|
||||
/**
|
||||
* @type {number?}
|
||||
* @private
|
||||
*/
|
||||
this.zoomBlocked_ = null;
|
||||
|
||||
};
|
||||
goog.inherits(ol.control.Navigation, ol.control.Control);
|
||||
|
||||
@@ -52,7 +58,7 @@ ol.control.Navigation.prototype.deactivate = function() {
|
||||
* @param {Object} evt
|
||||
*/
|
||||
ol.control.Navigation.prototype.moveMap = function(evt) {
|
||||
this.map_.moveByPx(evt.deltaX, evt.deltaY);
|
||||
this.map_.moveByViewportPx(evt.deltaX, evt.deltaY);
|
||||
return false;
|
||||
};
|
||||
|
||||
@@ -60,12 +66,17 @@ ol.control.Navigation.prototype.moveMap = function(evt) {
|
||||
* @param {Event} evt
|
||||
*/
|
||||
ol.control.Navigation.prototype.zoomMap = function(evt) {
|
||||
var map = this.map_,
|
||||
delta = ((evt.deltaY / 3) | 0);
|
||||
if (Math.abs(delta) === 0) {
|
||||
var me = this;
|
||||
if (evt.deltaY === 0 || me.zoomBlocked_) {
|
||||
return;
|
||||
}
|
||||
map.setZoom(map.getZoom()-delta, map.getEvents().getPointerPosition(evt));
|
||||
me.zoomBlocked_ = window.setTimeout(function() {
|
||||
me.zoomBlocked_ = null;
|
||||
}, 200);
|
||||
|
||||
var map = me.map_,
|
||||
step = evt.deltaY / Math.abs(evt.deltaY);
|
||||
map.setZoom(map.getZoom()-step, map.getEvents().getPointerPosition(evt));
|
||||
// We don't want the page to scroll.
|
||||
evt.preventDefault();
|
||||
return false;
|
||||
|
||||
@@ -12,13 +12,23 @@ goog.require('goog.dom');
|
||||
* @param {boolean|undefined} opt_autoActivate
|
||||
*/
|
||||
ol.control.Zoom = function(opt_autoActivate) {
|
||||
|
||||
|
||||
goog.base(this, opt_autoActivate);
|
||||
|
||||
/**
|
||||
* @type {Node}
|
||||
*/
|
||||
this.inButton_ = null;
|
||||
|
||||
/**
|
||||
* @type {Node}
|
||||
*/
|
||||
this.outButton_ = null;
|
||||
|
||||
/**
|
||||
* Activate this control when it is added to a map. Default is true.
|
||||
*
|
||||
* @type {boolean} autoActivate
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.autoActivate_ =
|
||||
goog.isDef(opt_autoActivate) ? opt_autoActivate : true;
|
||||
@@ -30,38 +40,38 @@ goog.inherits(ol.control.Zoom, ol.control.Control);
|
||||
* @param {ol.Map} map
|
||||
*/
|
||||
ol.control.Zoom.prototype.setMap = function(map) {
|
||||
goog.base(this, 'setMap', map);
|
||||
var container = goog.dom.createDom('div', ol.control.Zoom.RES.CLS);
|
||||
var inButton = goog.dom.createDom(
|
||||
this.inButton_ = goog.dom.createDom(
|
||||
'div', ol.control.Zoom.RES.IN_CLS,
|
||||
goog.dom.createDom('a', {'href': '#zoomIn'})
|
||||
);
|
||||
goog.dom.setTextContent(
|
||||
/** @type {Element} */ (inButton.firstChild),
|
||||
/** @type {Element} */ (this.inButton_.firstChild),
|
||||
ol.control.Zoom.RES.IN_TEXT
|
||||
);
|
||||
var outButton = goog.dom.createDom(
|
||||
this.outButton_ = goog.dom.createDom(
|
||||
'div', ol.control.Zoom.RES.OUT_CLS,
|
||||
goog.dom.createDom('a', {'href': '#zoomOut'})
|
||||
);
|
||||
goog.dom.setTextContent(
|
||||
/** @type {Element} */ (outButton.firstChild),
|
||||
/** @type {Element} */ (this.outButton_.firstChild),
|
||||
ol.control.Zoom.RES.OUT_TEXT
|
||||
);
|
||||
goog.dom.append(container, inButton, outButton);
|
||||
goog.dom.append(container, this.inButton_, this.outButton_);
|
||||
|
||||
var overlay = map.getStaticOverlay();
|
||||
if (goog.isDefAndNotNull(overlay)) {
|
||||
goog.dom.append(overlay, container);
|
||||
}
|
||||
goog.base(this, 'setMap', map);
|
||||
};
|
||||
|
||||
/** @inheritDoc */
|
||||
ol.control.Zoom.prototype.activate = function() {
|
||||
var active = goog.base(this, 'activate');
|
||||
if (active) {
|
||||
this.map_.getEvents().register('click', this.handle, this);
|
||||
this.map_.getEvents().register('keypress', this.handle, this);
|
||||
goog.events.listen(this.inButton_, 'click', this.handleIn, false, this);
|
||||
goog.events.listen(this.outButton_, 'click', this.handleOut, false, this);
|
||||
}
|
||||
return active;
|
||||
};
|
||||
@@ -70,37 +80,28 @@ ol.control.Zoom.prototype.activate = function() {
|
||||
ol.control.Zoom.prototype.deactivate = function() {
|
||||
var inactive = goog.base(this, 'deactivate');
|
||||
if (inactive) {
|
||||
this.map_.getEvents().unregister('click', this.handle, this);
|
||||
this.map_.getEvents().unregister('keypress', this.handle, this);
|
||||
goog.events.unlisten(this.inButton_, 'click', this.handleIn, false, this);
|
||||
goog.events.unlisten(this.outButton_, 'click', this.handleOut, false, this);
|
||||
}
|
||||
return inactive;
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {Event} evt
|
||||
* @return {boolean}
|
||||
*/
|
||||
ol.control.Zoom.prototype.handle = function(evt) {
|
||||
var target = /** @type {Node} */ (evt.target),
|
||||
handled = false;
|
||||
if (evt.type === 'click' || ol.event.isEnterOrSpace(evt)) {
|
||||
if (goog.dom.getAncestorByClass(target, ol.control.Zoom.RES.IN_CLS)) {
|
||||
this.map_.zoomIn();
|
||||
handled = true;
|
||||
} else
|
||||
if (goog.dom.getAncestorByClass(target, ol.control.Zoom.RES.OUT_CLS)) {
|
||||
this.map_.zoomOut();
|
||||
handled = true;
|
||||
}
|
||||
if (handled) {
|
||||
// Stop default behavior (i.e. don't follow link to anchor)
|
||||
evt.preventDefault();
|
||||
// On Android 2.3, the above does not prevent the link from being
|
||||
// followed, but stopPropagation does.
|
||||
evt.stopPropagation();
|
||||
}
|
||||
}
|
||||
return !handled;
|
||||
ol.control.Zoom.prototype.handleIn = function(evt) {
|
||||
this.map_.zoomIn();
|
||||
evt.preventDefault();
|
||||
evt.stopPropagation();
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {Event} evt
|
||||
*/
|
||||
ol.control.Zoom.prototype.handleOut = function(evt) {
|
||||
this.map_.zoomOut();
|
||||
evt.preventDefault();
|
||||
evt.stopPropagation();
|
||||
};
|
||||
|
||||
ol.control.Zoom.prototype.destroy = function() {
|
||||
|
||||
95
src/ol/event/Drag.js
Normal file
95
src/ol/event/Drag.js
Normal file
@@ -0,0 +1,95 @@
|
||||
goog.provide('ol.event.Drag');
|
||||
|
||||
goog.require('ol.event');
|
||||
goog.require('ol.event.ISequence');
|
||||
|
||||
goog.require('goog.functions');
|
||||
goog.require('goog.fx.Dragger');
|
||||
goog.require('goog.fx.DragEvent');
|
||||
goog.require('goog.fx.Dragger.EventType');
|
||||
|
||||
|
||||
/**
|
||||
* Event sequence that provides a 'dragstart', 'drag' and 'dragend' events.
|
||||
* Event objects of the 'drag' events have 'deltaX' and 'deltaY' values with
|
||||
* the relative pixel movement since the previous 'drag' or 'dragstart' event.
|
||||
*
|
||||
* @constructor
|
||||
* @param {ol.event.Events} target The Events instance that handles events.
|
||||
* @implements {ol.event.ISequence}
|
||||
* @export
|
||||
*/
|
||||
ol.event.Drag = function(target) {
|
||||
var previousX = 0, previousY = 0,
|
||||
element = target.getElement(),
|
||||
dragger = new goog.fx.Dragger(element);
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {goog.fx.Dragger}
|
||||
*/
|
||||
this.dragger_ = dragger;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {ol.event.Events}
|
||||
*/
|
||||
this.target_ = target;
|
||||
|
||||
// We want to swallow the click event that gets fired after dragging.
|
||||
var newSequence;
|
||||
function unregisterClickStopper() {
|
||||
target.unregister('click', goog.functions.FALSE, undefined, true);
|
||||
}
|
||||
|
||||
// no default for mousemove and touchmove events to avoid page scrolling.
|
||||
target.register('mousemove', ol.event.preventDefault);
|
||||
target.register('touchmove', ol.event.preventDefault);
|
||||
|
||||
dragger.defaultAction = function(x, y) {};
|
||||
dragger.addEventListener(goog.fx.Dragger.EventType.START, function(evt) {
|
||||
evt.target = element;
|
||||
evt.type = 'dragstart';
|
||||
previousX = evt.clientX;
|
||||
previousY = evt.clientY;
|
||||
newSequence = true;
|
||||
target.triggerEvent(evt.type, evt);
|
||||
});
|
||||
dragger.addEventListener(goog.fx.Dragger.EventType.DRAG, function(evt) {
|
||||
evt.target = element;
|
||||
evt.deltaX = evt.clientX - previousX;
|
||||
evt.deltaY = evt.clientY - previousY;
|
||||
previousX = evt.clientX;
|
||||
previousY = evt.clientY;
|
||||
if (newSequence) {
|
||||
// Once we are in the drag sequence, we know that we need to
|
||||
// get rid of the click event that gets fired when we are done
|
||||
// dragging.
|
||||
target.register('click', goog.functions.FALSE, undefined, true);
|
||||
newSequence = false;
|
||||
}
|
||||
target.triggerEvent(evt.type, evt);
|
||||
});
|
||||
dragger.addEventListener(goog.fx.Dragger.EventType.END, function(evt) {
|
||||
evt.target = element;
|
||||
evt.type = 'dragend';
|
||||
target.triggerEvent(evt.type, evt);
|
||||
// Unregister the click stopper in the next cycle
|
||||
window.setTimeout(unregisterClickStopper, 0);
|
||||
});
|
||||
// Don't swallow the click event if our sequence cancels early.
|
||||
dragger.addEventListener(
|
||||
goog.fx.Dragger.EventType.EARLY_CANCEL, unregisterClickStopper
|
||||
);
|
||||
};
|
||||
|
||||
/** @inheritDoc */
|
||||
ol.event.Drag.prototype.destroy = function() {
|
||||
this.target_.unregister('mousemove', ol.event.preventDefault);
|
||||
this.target_.unregister('touchmove', ol.event.preventDefault);
|
||||
this.dragger_.dispose();
|
||||
goog.object.clear(this);
|
||||
};
|
||||
|
||||
|
||||
ol.event.addSequenceProvider('drag', ol.event.Drag);
|
||||
@@ -42,16 +42,21 @@ ol.event.isMultiTouch = function(evt) {
|
||||
};
|
||||
|
||||
/**
|
||||
* Is the event a keyboard event with Enter or Space pressed?
|
||||
* Call preventDefault on the provided event.
|
||||
*
|
||||
* @param {!Event} evt
|
||||
* @return {boolean}
|
||||
*/
|
||||
ol.event.isEnterOrSpace = function(evt) {
|
||||
return evt.type === "keypress" &&
|
||||
(evt.keyCode === goog.events.KeyCodes.ENTER ||
|
||||
evt.keyCode === goog.events.KeyCodes.SPACE ||
|
||||
evt.keyCode === goog.events.KeyCodes.MAC_ENTER);
|
||||
ol.event.preventDefault = function(evt) {
|
||||
evt.preventDefault();
|
||||
};
|
||||
|
||||
/**
|
||||
* Call stopPropagation on the provided event.
|
||||
*
|
||||
* @param {!Event} evt
|
||||
*/
|
||||
ol.event.stopPropagation = function(evt) {
|
||||
evt.stopPropagation();
|
||||
};
|
||||
|
||||
|
||||
@@ -155,7 +160,7 @@ ol.event.Events.prototype.setElement = function(element) {
|
||||
if (this.element_) {
|
||||
for (t in types) {
|
||||
goog.events.unlisten(
|
||||
this.element_, types[t], this.handleBrowserEvent, true, this
|
||||
this.element_, types[t], this.handleBrowserEvent, false, this
|
||||
);
|
||||
}
|
||||
this.destroySequences();
|
||||
@@ -166,7 +171,7 @@ ol.event.Events.prototype.setElement = function(element) {
|
||||
this.createSequences();
|
||||
for (t in types) {
|
||||
goog.events.listen(
|
||||
element, types[t], this.handleBrowserEvent, true, this
|
||||
element, types[t], this.handleBrowserEvent, false, this
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,11 @@ goog.require('ol.renderer.MapRenderer');
|
||||
goog.require('ol.renderer.LayerRenderer');
|
||||
goog.require('ol.layer.Layer');
|
||||
goog.require('ol.Loc');
|
||||
|
||||
goog.require('goog.array');
|
||||
goog.require('goog.dom');
|
||||
goog.require('goog.style');
|
||||
goog.require('goog.math.Coordinate');
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
@@ -21,21 +25,43 @@ ol.renderer.Composite = function(container) {
|
||||
*/
|
||||
this.renderers_ = [];
|
||||
|
||||
var target = document.createElement("div");
|
||||
target.className = "ol-renderer-composite";
|
||||
target.style.position = "absolute";
|
||||
target.style.height = "100%";
|
||||
target.style.width = "100%";
|
||||
container.appendChild(target);
|
||||
|
||||
/**
|
||||
* @type Element
|
||||
* Pixel buffer for renderer container.
|
||||
*
|
||||
* @type {number}
|
||||
* @private
|
||||
*/
|
||||
this.target_ = target;
|
||||
this.buffer_ = 128;
|
||||
|
||||
/**
|
||||
* @type {Element}
|
||||
* @private
|
||||
*/
|
||||
this.target_ = null;
|
||||
|
||||
/**
|
||||
* The current top left corner location of the target element (map coords).
|
||||
*
|
||||
* @type {ol.Loc}
|
||||
* @private
|
||||
*/
|
||||
this.targetOrigin_ = null;
|
||||
|
||||
/**
|
||||
* The pixel offset of the target element with respect to its container.
|
||||
*
|
||||
* @type {goog.math.Coordinate}
|
||||
* @private
|
||||
*/
|
||||
this.targetOffset_ = null;
|
||||
|
||||
/**
|
||||
* @type {Object}
|
||||
* @private
|
||||
*/
|
||||
this.layerContainers_ = {};
|
||||
|
||||
};
|
||||
|
||||
goog.inherits(ol.renderer.Composite, ol.renderer.MapRenderer);
|
||||
|
||||
/**
|
||||
@@ -45,22 +71,129 @@ goog.inherits(ol.renderer.Composite, ol.renderer.MapRenderer);
|
||||
* @param {boolean} animate
|
||||
*/
|
||||
ol.renderer.Composite.prototype.draw = function(layers, center, resolution, animate) {
|
||||
if (goog.isNull(this.target_)) {
|
||||
// first rendering
|
||||
this.createTarget_(center, resolution);
|
||||
}
|
||||
|
||||
// TODO: deal with layer order and removal
|
||||
for (var i=0, ii=layers.length; i<ii; ++i) {
|
||||
this.getOrCreateRenderer(layers[i], i).draw(center, resolution);
|
||||
|
||||
if (this.renderedResolution_) {
|
||||
if (resolution !== this.renderedResolution_) {
|
||||
// TODO: apply transition to old target
|
||||
this.resetTarget_(center, resolution);
|
||||
}
|
||||
}
|
||||
this.renderedResolution_ = resolution;
|
||||
|
||||
// shift target element to account for center change
|
||||
if (this.renderedCenter_) {
|
||||
this.shiftTarget_(center, resolution);
|
||||
}
|
||||
this.renderedCenter_ = center;
|
||||
this.renderedResolution_ = resolution;
|
||||
|
||||
// update each layer renderer
|
||||
var renderer;
|
||||
for (var i=0, ii=layers.length; i<ii; ++i) {
|
||||
renderer = this.getOrCreateRenderer_(layers[i], i);
|
||||
renderer.draw(center, resolution);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a new target element for layer renderer containers.
|
||||
*
|
||||
* @param {ol.Loc} center
|
||||
* @param {number} resolution
|
||||
*/
|
||||
ol.renderer.Composite.prototype.createTarget_ = function(center, resolution) {
|
||||
this.targetOrigin_ = this.getOriginForCenterAndRes_(center, resolution);
|
||||
|
||||
var containerSize = this.getContainerSize();
|
||||
var containerWidth = containerSize.width;
|
||||
var containerHeight = containerSize.height;
|
||||
var buffer = this.buffer_;
|
||||
|
||||
var targetWidth = containerWidth + (2 * buffer);
|
||||
var targetHeight = containerHeight + (2 * buffer);
|
||||
var offset = new goog.math.Coordinate(-buffer, -buffer);
|
||||
|
||||
var target = goog.dom.createDom('div', {
|
||||
'class': 'ol-renderer-composite',
|
||||
'style': 'width:' + targetWidth + 'px;height:' + targetHeight + 'px;' +
|
||||
'top:' + offset.y + 'px;left:' + offset.x + 'px;' +
|
||||
'position:absolute'
|
||||
});
|
||||
this.target_ = target;
|
||||
this.targetOffset_ = offset;
|
||||
this.renderedCenter_ = center;
|
||||
goog.dom.appendChild(this.container_, target);
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {ol.Loc} center
|
||||
* @param {number} resolution
|
||||
* @return {ol.Loc}
|
||||
*/
|
||||
ol.renderer.Composite.prototype.getOriginForCenterAndRes_ = function(center, resolution) {
|
||||
var containerSize = this.getContainerSize();
|
||||
var containerWidth = containerSize.width;
|
||||
var containerHeight = containerSize.height;
|
||||
var buffer = this.buffer_;
|
||||
var targetWidth = containerWidth + (2 * buffer);
|
||||
var targetHeight = containerHeight + (2 * buffer);
|
||||
return new ol.Loc(
|
||||
center.getX() - (resolution * targetWidth / 2),
|
||||
center.getY() + (resolution * targetHeight / 2)
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Adjust the position of the renderer target given the new center.
|
||||
*
|
||||
* @param {ol.Loc} center
|
||||
* @param {number} resolution
|
||||
*/
|
||||
ol.renderer.Composite.prototype.shiftTarget_ = function(center, resolution) {
|
||||
var oldCenter = this.renderedCenter_;
|
||||
var dx = Math.round((oldCenter.getX() - center.getX()) / resolution);
|
||||
var dy = Math.round((center.getY() - oldCenter.getY()) / resolution);
|
||||
if (!(dx == 0 && dy == 0)) {
|
||||
var offset = this.targetOffset_;
|
||||
offset.x += Math.round((oldCenter.getX() - center.getX()) / resolution);
|
||||
offset.y += Math.round((center.getY() - oldCenter.getY()) / resolution);
|
||||
goog.style.setPosition(this.target_, offset);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Reposition the target element back to the original offset.
|
||||
*
|
||||
* @param {ol.Loc} center
|
||||
* @param {number} resolution
|
||||
*/
|
||||
ol.renderer.Composite.prototype.resetTarget_ = function(center, resolution) {
|
||||
this.targetOrigin_ = this.getOriginForCenterAndRes_(center, resolution);
|
||||
for (var i=0, ii=this.renderers_.length; i<ii; ++i) {
|
||||
this.renderers_[i].setContainerOrigin(this.targetOrigin_);
|
||||
}
|
||||
var offset = new goog.math.Coordinate(-this.buffer_, -this.buffer_);
|
||||
this.targetOffset_ = offset;
|
||||
this.renderedCenter_ = center;
|
||||
goog.style.setPosition(this.target_, offset);
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @param {ol.layer.Layer} layer
|
||||
* @param {number} index
|
||||
*/
|
||||
ol.renderer.Composite.prototype.getOrCreateRenderer = function(layer, index) {
|
||||
var renderer = this.getRenderer(layer);
|
||||
ol.renderer.Composite.prototype.getOrCreateRenderer_ = function(layer, index) {
|
||||
var renderer = this.getRenderer_(layer);
|
||||
if (goog.isNull(renderer)) {
|
||||
renderer = this.createRenderer(layer);
|
||||
renderer = this.createRenderer_(layer);
|
||||
goog.array.insertAt(this.renderers_, renderer, index);
|
||||
}
|
||||
return renderer;
|
||||
@@ -68,21 +201,42 @@ ol.renderer.Composite.prototype.getOrCreateRenderer = function(layer, index) {
|
||||
|
||||
/**
|
||||
* @param {ol.layer.Layer} layer
|
||||
* @return {ol.renderer.LayerRenderer}
|
||||
*/
|
||||
ol.renderer.Composite.prototype.getRenderer = function(layer) {
|
||||
ol.renderer.Composite.prototype.getRenderer_ = function(layer) {
|
||||
function finder(candidate) {
|
||||
return candidate.getLayer() === layer;
|
||||
}
|
||||
return goog.array.find(this.renderers_, finder);
|
||||
var renderer = goog.array.find(this.renderers_, finder);
|
||||
return /** @type {ol.renderer.LayerRenderer} */ renderer;
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {ol.layer.Layer} layer
|
||||
*/
|
||||
ol.renderer.Composite.prototype.createRenderer = function(layer) {
|
||||
ol.renderer.Composite.prototype.createRenderer_ = function(layer) {
|
||||
var Renderer = this.pickRendererType(layer);
|
||||
goog.asserts.assert(Renderer, "No supported renderer for layer: " + layer);
|
||||
return new Renderer(this.target_, layer);
|
||||
|
||||
var container = goog.dom.createDom('div', {
|
||||
'class': 'ol-renderer-composite-layer',
|
||||
'style': 'width:100%;height:100%;top:0;left:0;position:absolute'
|
||||
});
|
||||
goog.dom.appendChild(this.target_, container);
|
||||
var renderer = new Renderer(container, layer);
|
||||
renderer.setContainerOrigin(this.targetOrigin_);
|
||||
this.layerContainers_[goog.getUid(renderer)] = container;
|
||||
return renderer;
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {ol.renderer.LayerRenderer} renderer
|
||||
* @return {Element}
|
||||
*/
|
||||
ol.renderer.Composite.prototype.getRendererContainer_ = function(renderer) {
|
||||
var container = this.layerContainers_[goog.getUid(renderer)];
|
||||
goog.asserts.assert(goog.isDef(container));
|
||||
return container;
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
goog.provide('ol.renderer.LayerRenderer');
|
||||
|
||||
goog.require('goog.math.Coordinate');
|
||||
goog.require('goog.math.Size');
|
||||
|
||||
/**
|
||||
* A single layer renderer that will be created by the composite map renderer.
|
||||
*
|
||||
@@ -15,24 +18,48 @@ ol.renderer.LayerRenderer = function(container, layer) {
|
||||
*/
|
||||
this.container_ = container;
|
||||
|
||||
/**
|
||||
* @type {goog.math.Size}
|
||||
* @private
|
||||
*/
|
||||
this.containerSize_ = null;
|
||||
|
||||
/**
|
||||
* Location of the top-left corner of the renderer container in map coords.
|
||||
*
|
||||
* @type {ol.Loc}
|
||||
* @protected
|
||||
*/
|
||||
this.containerOrigin_ = null;
|
||||
|
||||
/**
|
||||
* @type {!ol.layer.Layer}
|
||||
* @protected
|
||||
*/
|
||||
this.layer_ = layer;
|
||||
|
||||
var target = goog.dom.createDom('div', {
|
||||
'class': 'ol-renderer-layer',
|
||||
'style': 'position:absolute;height:1px:width:1px'
|
||||
});
|
||||
goog.dom.appendChild(container, target);
|
||||
};
|
||||
|
||||
/**
|
||||
* @type Element
|
||||
* @protected
|
||||
*/
|
||||
this.target_ = target;
|
||||
|
||||
/**
|
||||
* @return {goog.math.Size}
|
||||
* @protected
|
||||
*/
|
||||
ol.renderer.LayerRenderer.prototype.getContainerSize = function() {
|
||||
// TODO: listen for resize and set this.constainerSize_ null
|
||||
// https://github.com/openlayers/ol3/issues/2
|
||||
if (goog.isNull(this.containerSize_)) {
|
||||
this.containerSize_ = goog.style.getSize(this.container_);
|
||||
}
|
||||
return this.containerSize_;
|
||||
};
|
||||
|
||||
/**
|
||||
* Set the location of the top-left corner of the renderer container.
|
||||
*
|
||||
* @param {ol.Loc} origin The container origin.
|
||||
*/
|
||||
ol.renderer.LayerRenderer.prototype.setContainerOrigin = function(origin) {
|
||||
this.containerOrigin_ = origin;
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
goog.provide('ol.renderer.MapRenderer');
|
||||
|
||||
goog.require('goog.style');
|
||||
goog.require('goog.math.Size');
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
@@ -13,6 +14,12 @@ ol.renderer.MapRenderer = function(container) {
|
||||
* @protected
|
||||
*/
|
||||
this.container_ = container;
|
||||
|
||||
/**
|
||||
* @type {goog.math.Size}
|
||||
* @private
|
||||
*/
|
||||
this.containerSize_ = null;
|
||||
|
||||
/**
|
||||
* @type {ol.Loc}
|
||||
@@ -28,6 +35,20 @@ ol.renderer.MapRenderer = function(container) {
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* @return {goog.math.Size}
|
||||
* @protected
|
||||
*/
|
||||
ol.renderer.MapRenderer.prototype.getContainerSize = function() {
|
||||
// TODO: listen for resize and set this.constainerSize_ null
|
||||
// https://github.com/openlayers/ol3/issues/2
|
||||
if (goog.isNull(this.containerSize_)) {
|
||||
this.containerSize_ = goog.style.getSize(this.container_);
|
||||
}
|
||||
return this.containerSize_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {Array.<ol.layer.Layer>} layers
|
||||
* @param {ol.Loc} center
|
||||
@@ -37,6 +58,13 @@ ol.renderer.MapRenderer = function(container) {
|
||||
ol.renderer.MapRenderer.prototype.draw = function(layers, center, resolution, animate) {
|
||||
};
|
||||
|
||||
/**
|
||||
* @return {number} The rendered resolution.
|
||||
*/
|
||||
ol.renderer.MapRenderer.prototype.getResolution = function() {
|
||||
return this.renderedResolution_;
|
||||
};
|
||||
|
||||
/**
|
||||
* TODO: determine a closure friendly way to register map renderers.
|
||||
* @type {Array}
|
||||
@@ -80,38 +108,3 @@ ol.renderer.MapRenderer.pickRendererType = function(preferences) {
|
||||
// if we didn't find any of the preferred renderers, use the first
|
||||
return Renderer || Candidates[0] || null;
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {goog.math.Coordinate|{x: number, y: number}} pixel
|
||||
* @return {ol.Loc}
|
||||
*/
|
||||
ol.renderer.MapRenderer.prototype.getLocForPixel = function(pixel) {
|
||||
var center = this.renderedCenter_,
|
||||
resolution = this.renderedResolution_,
|
||||
size = goog.style.getSize(this.container_);
|
||||
return center.add(
|
||||
(pixel.x - size.width/2) * resolution,
|
||||
(size.height/2 - pixel.y) * resolution
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {ol.Loc} loc
|
||||
* @return {{x: number, y: number}}
|
||||
*/
|
||||
ol.renderer.MapRenderer.prototype.getPixelForLoc = function(loc) {
|
||||
var center = this.renderedCenter_,
|
||||
resolution = this.renderedResolution_,
|
||||
size = this.getSize();
|
||||
return {
|
||||
x: (size.width*resolution/2 + loc.getX() - center.getX())/resolution,
|
||||
y: (size.height*resolution/2 - loc.getY() + center.getY())/resolution
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* @return {goog.math.Size} The currently rendered map size in pixels.
|
||||
*/
|
||||
ol.renderer.MapRenderer.prototype.getSize = function() {
|
||||
return goog.style.getSize(this.container_);
|
||||
};
|
||||
|
||||
@@ -7,6 +7,7 @@ goog.require('ol.TileSet');
|
||||
goog.require('ol.Bounds');
|
||||
|
||||
goog.require('goog.style');
|
||||
goog.require('goog.math.Box');
|
||||
|
||||
|
||||
/**
|
||||
@@ -37,14 +38,14 @@ ol.renderer.TileLayerRenderer = function(container, layer) {
|
||||
this.tileSize_ = layer.getTileSize();
|
||||
|
||||
/**
|
||||
* @type {number}
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.xRight_ = layer.getXRight() ? 1 : -1;
|
||||
this.xRight_ = layer.getXRight();
|
||||
|
||||
/**
|
||||
* @type {number}
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.yDown_ = layer.getYDown() ? 1 : -1;
|
||||
this.yDown_ = layer.getYDown();
|
||||
|
||||
/**
|
||||
* @type {number|undefined}
|
||||
@@ -52,86 +53,15 @@ ol.renderer.TileLayerRenderer = function(container, layer) {
|
||||
*/
|
||||
this.renderedResolution_ = undefined;
|
||||
|
||||
/**
|
||||
* @type {number|undefined}
|
||||
* @private
|
||||
*/
|
||||
this.renderedTop_ = undefined;
|
||||
|
||||
/**
|
||||
* @type {number|undefined}
|
||||
* @private
|
||||
*/
|
||||
this.renderedRight_ = undefined;
|
||||
|
||||
/**
|
||||
* @type {number|undefined}
|
||||
* @private
|
||||
*/
|
||||
this.renderedBottom_ = undefined;
|
||||
|
||||
/**
|
||||
* @type {number|undefined}
|
||||
* @private
|
||||
*/
|
||||
this.renderedLeft_ = undefined;
|
||||
|
||||
/**
|
||||
* @type {number|undefined}
|
||||
* @private
|
||||
*/
|
||||
this.renderedZ_ = undefined;
|
||||
|
||||
/**
|
||||
* @type {goog.math.Size}
|
||||
* @private
|
||||
*/
|
||||
this.containerSize_ = null;
|
||||
|
||||
};
|
||||
|
||||
goog.inherits(ol.renderer.TileLayerRenderer, ol.renderer.LayerRenderer);
|
||||
|
||||
/**
|
||||
* @param {number} resolution
|
||||
* @return {Array.<number>}
|
||||
*/
|
||||
ol.renderer.TileLayerRenderer.prototype.getPreferredResAndZ_ = function(resolution) {
|
||||
var minDiff = Number.POSITIVE_INFINITY;
|
||||
var candidate, diff, z, r;
|
||||
for (var i=0, ii=this.layerResolutions_.length; i<ii; ++i) {
|
||||
// assumes sorted resolutions
|
||||
candidate = this.layerResolutions_[i];
|
||||
diff = Math.abs(resolution - candidate);
|
||||
if (diff < minDiff) {
|
||||
z = i;
|
||||
r = candidate;
|
||||
minDiff = diff;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return [r, z];
|
||||
};
|
||||
|
||||
/**
|
||||
* @return {goog.math.Size}
|
||||
*/
|
||||
ol.renderer.TileLayerRenderer.prototype.getContainerSize_ = function() {
|
||||
// TODO: listen for resize and set this.constainerSize_ null
|
||||
// https://github.com/openlayers/ol3/issues/2
|
||||
if (goog.isNull(this.containerSize_)) {
|
||||
this.containerSize_ = goog.style.getSize(this.container_);
|
||||
}
|
||||
return this.containerSize_;
|
||||
};
|
||||
|
||||
/**
|
||||
* Tiles rendered at the current resolution;
|
||||
* @type {Object}
|
||||
*/
|
||||
ol.renderer.TileLayerRenderer.prototype.renderedTiles_ = {};
|
||||
|
||||
/**
|
||||
* Render the layer.
|
||||
*
|
||||
@@ -140,152 +70,234 @@ ol.renderer.TileLayerRenderer.prototype.renderedTiles_ = {};
|
||||
*/
|
||||
ol.renderer.TileLayerRenderer.prototype.draw = function(center, resolution) {
|
||||
if (resolution !== this.renderedResolution_) {
|
||||
this.changeResolution_(center, resolution);
|
||||
this.changeResolution_(resolution);
|
||||
}
|
||||
var pair = this.getPreferredResAndZ_(resolution);
|
||||
var tileResolution = pair[0];
|
||||
var tileZ = pair[1];
|
||||
var scale = resolution / tileResolution;
|
||||
|
||||
var pxMapSize = this.getContainerSize_();
|
||||
var xRight = this.xRight_;
|
||||
var yDown = this.yDown_;
|
||||
var z = this.renderedZ_;
|
||||
var tileOrigin = this.tileOrigin_;
|
||||
|
||||
var halfMapWidth = (resolution * pxMapSize.width) / 2;
|
||||
var halfMapHeight = (resolution * pxMapSize.height) / 2;
|
||||
var centerX = center.getX();
|
||||
var centerY = center.getY();
|
||||
var mapMinX = centerX - halfMapWidth;
|
||||
var mapMaxY = centerY + halfMapHeight;
|
||||
var pxOffsetX = Math.round((mapMinX - this.tileOrigin_[0]) / resolution);
|
||||
var pxOffsetY = Math.round((this.tileOrigin_[1] - mapMaxY) / resolution);
|
||||
|
||||
// this gives us the desired size in fractional pixels
|
||||
var pxTileWidth = this.tileSize_[0] / scale;
|
||||
var pxTileHeight = this.tileSize_[1] / scale;
|
||||
|
||||
// this is the index of the top left tile
|
||||
var leftTileX = Math.floor(xRight * pxOffsetX / pxTileWidth);
|
||||
var topTileY = Math.floor(yDown * pxOffsetY / pxTileHeight);
|
||||
var offset = this.getTileOffset_();
|
||||
var tileBox = this.getTileBox_(center, resolution);
|
||||
|
||||
var pxMinX;
|
||||
if (xRight > 0) {
|
||||
pxMinX = Math.round(leftTileX * pxTileWidth) - pxOffsetX;
|
||||
} else {
|
||||
pxMinX = Math.round((-leftTileX-1) * pxTileWidth) - pxOffsetX;
|
||||
}
|
||||
var pxMinY;
|
||||
if (yDown > 0) {
|
||||
pxMinY = Math.round(topTileY * pxTileHeight) - pxOffsetY;
|
||||
} else {
|
||||
pxMinY = Math.round((-topTileY-1) * pxTileHeight) - pxOffsetY;
|
||||
}
|
||||
|
||||
var pxTileLeft = pxMinX;
|
||||
var pxTileTop = pxMinY;
|
||||
|
||||
var numTilesWide = Math.ceil(pxMapSize.width / pxTileWidth);
|
||||
var numTilesHigh = Math.ceil(pxMapSize.height / pxTileHeight);
|
||||
|
||||
// assume a buffer of zero for now
|
||||
if (pxMinX < 0) {
|
||||
numTilesWide += 1;
|
||||
}
|
||||
if (pxMinY < 0) {
|
||||
numTilesHigh += 1;
|
||||
}
|
||||
|
||||
var tileX, tileY, tile, img, pxTileRight, pxTileBottom, xyz, append;
|
||||
var fragment = document.createDocumentFragment();
|
||||
var newTiles = false;
|
||||
for (var i=0; i<numTilesWide; ++i) {
|
||||
pxTileTop = pxMinY;
|
||||
tileX = leftTileX + (i * xRight);
|
||||
if (scale !== 1) {
|
||||
pxTileRight = Math.round(pxMinX + ((i+1) * pxTileWidth));
|
||||
} else {
|
||||
pxTileRight = pxTileLeft + pxTileWidth;
|
||||
}
|
||||
for (var j=0; j<numTilesHigh; ++j) {
|
||||
append = false;
|
||||
tileY = topTileY + (j * yDown);
|
||||
xyz = tileX + "," + tileY + "," + tileZ;
|
||||
if (scale !== 1) {
|
||||
pxTileBottom = Math.round(pxMinY + ((j+1) * pxTileHeight));
|
||||
} else {
|
||||
pxTileBottom = pxTileTop + pxTileHeight;
|
||||
}
|
||||
img = null;
|
||||
tile = this.renderedTiles_[xyz];
|
||||
var ijz, key, tile, xyz, box, img, newTiles = false;
|
||||
for (var i=tileBox.left; i<tileBox.right; ++i) {
|
||||
for (var j=tileBox.top; j<tileBox.bottom; ++j) {
|
||||
ijz = [i, j, z];
|
||||
key = ijz.join(",");
|
||||
tile = this.renderedTiles_[key];
|
||||
if (!tile) {
|
||||
tile = this.layer_.getTileForXYZ(tileX, tileY, tileZ);
|
||||
xyz = this.getTileCoordsFromNormalizedCoords_(ijz);
|
||||
tile = this.layer_.getTileForXYZ(xyz[0], xyz[1], xyz[2]);
|
||||
if (tile) {
|
||||
if (!tile.isLoaded() && !tile.isLoading()) {
|
||||
tile.load();
|
||||
}
|
||||
this.renderedTiles_[xyz] = tile;
|
||||
this.renderedTiles_[key] = tile;
|
||||
box = this.getTilePixelBox_(ijz, resolution);
|
||||
img = tile.getImg();
|
||||
img.style.top = (box.top - offset.y) + "px";
|
||||
img.style.left = (box.left - offset.x) + "px";
|
||||
/**
|
||||
* We need to set the size here even if the scale is 1
|
||||
* because the image may have been scaled previously. If
|
||||
* we want to avoid setting size unnecessarily, the tile
|
||||
* should keep track of the scale.
|
||||
*/
|
||||
img.style.height = (box.bottom - box.top) + "px";
|
||||
img.style.width = (box.right - box.left) + "px";
|
||||
goog.dom.appendChild(fragment, img);
|
||||
newTiles = true;
|
||||
}
|
||||
} else {
|
||||
img = tile.getImg();
|
||||
}
|
||||
if (img) {
|
||||
img.style.top = pxTileTop + "px";
|
||||
img.style.left = pxTileLeft + "px";
|
||||
if (scale !== 1) {
|
||||
img.style.height = (pxTileRight - pxTileLeft) + "px";
|
||||
img.style.width = (pxTileBottom - pxTileTop) + "px";
|
||||
}
|
||||
}
|
||||
pxTileTop = pxTileBottom;
|
||||
}
|
||||
pxTileLeft = pxTileRight;
|
||||
}
|
||||
if (newTiles) {
|
||||
this.target_.appendChild(fragment);
|
||||
this.container_.appendChild(fragment);
|
||||
}
|
||||
this.renderedResolution_ = resolution;
|
||||
this.renderedTop_ = topTileY;
|
||||
this.renderedRight_ = tileX;
|
||||
this.renderedBottom_ = tileY;
|
||||
this.renderedLeft_ = leftTileX;
|
||||
this.renderedZ_ = tileZ;
|
||||
|
||||
this.renderedTileBox_ = tileBox;
|
||||
this.removeInvisibleTiles_();
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the pixel offset between the tile origin and the container origin.
|
||||
* TODO: cache this and invalidate it with changes to the container origin.
|
||||
*
|
||||
* @return {goog.math.Coordinate}
|
||||
*/
|
||||
ol.renderer.TileLayerRenderer.prototype.getTileOffset_ = function() {
|
||||
var resolution = this.renderedResolution_;
|
||||
return new goog.math.Coordinate(
|
||||
Math.round((this.containerOrigin_.getX() - this.tileOrigin_[0]) / resolution),
|
||||
Math.round((this.tileOrigin_[1] - this.containerOrigin_.getY()) / resolution)
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {Array.<number>} ijz
|
||||
* @param {number} resolution
|
||||
* @return {goog.math.Box}
|
||||
*/
|
||||
ol.renderer.TileLayerRenderer.prototype.getTilePixelBox_ = function(ijz, resolution) {
|
||||
var tileResolution = this.layerResolutions_[ijz[2]];
|
||||
var scale = resolution / tileResolution;
|
||||
var tileSize = this.tileSize_;
|
||||
|
||||
// desired tile size (in fractional pixels)
|
||||
var fpxTileWidth = tileSize[0] / scale;
|
||||
var fpxTileHeight = tileSize[1] / scale;
|
||||
|
||||
var col = ijz[0];
|
||||
var left = Math.round(col * fpxTileWidth); // inclusive
|
||||
var right = Math.round((col + 1) * fpxTileWidth); // exclusive
|
||||
|
||||
var row = ijz[1];
|
||||
var top = Math.round(row * fpxTileHeight); // inclusive
|
||||
var bottom = Math.round((row + 1) * fpxTileWidth); // exclusive
|
||||
|
||||
return new goog.math.Box(top, right, bottom, left);
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {ol.Loc} loc
|
||||
* @param {number} resolution
|
||||
* @return {goog.math.Coordinate}
|
||||
*/
|
||||
ol.renderer.TileLayerRenderer.prototype.getNormalizedTileCoord_ = function(loc, resolution) {
|
||||
var tileOrigin = this.tileOrigin_;
|
||||
var tileSize = this.tileSize_;
|
||||
var pair = this.getPreferredResAndZ_(resolution);
|
||||
var tileResolution = pair[0];
|
||||
var z = pair[1];
|
||||
var scale = resolution / tileResolution;
|
||||
|
||||
// offset from tile origin in pixel space
|
||||
var dx = Math.round((loc.getX() - tileOrigin[0]) / resolution);
|
||||
var dy = Math.round((tileOrigin[1] - loc.getY()) / resolution);
|
||||
|
||||
// desired tile size (in fractional pixels)
|
||||
var fpxTileWidth = tileSize[0] / scale;
|
||||
var fpxTileHeight = tileSize[1] / scale;
|
||||
|
||||
// determine normalized col number (0 based, ascending right)
|
||||
var col = Math.floor(dx / fpxTileWidth);
|
||||
// determine normalized row number (0 based, ascending down)
|
||||
var row = Math.floor(dy / fpxTileHeight);
|
||||
|
||||
var box = this.getTilePixelBox_([col, row, z], resolution);
|
||||
|
||||
// adjust col to allow for stretched tiles
|
||||
if (dx < box.left) {
|
||||
col -= 1;
|
||||
} else if (dx >= box.right) {
|
||||
col += 1;
|
||||
}
|
||||
|
||||
// adjust row to allow for stretched tiles
|
||||
if (dy < box.top) {
|
||||
row -= 1;
|
||||
} else if (dy >= box.bottom) {
|
||||
row += 1;
|
||||
}
|
||||
|
||||
return new goog.math.Coordinate(col, row);
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {number} resolution
|
||||
* @return {Array.<number>}
|
||||
*/
|
||||
ol.renderer.TileLayerRenderer.prototype.getPreferredResAndZ_ = (function() {
|
||||
var cache = {};
|
||||
return function(resolution) {
|
||||
if (resolution in cache) {
|
||||
return cache[resolution];
|
||||
}
|
||||
var minDiff = Number.POSITIVE_INFINITY;
|
||||
var candidate, diff, z, r;
|
||||
for (var i=0, ii=this.layerResolutions_.length; i<ii; ++i) {
|
||||
// assumes sorted resolutions
|
||||
candidate = this.layerResolutions_[i];
|
||||
diff = Math.abs(resolution - candidate);
|
||||
if (diff < minDiff) {
|
||||
z = i;
|
||||
r = candidate;
|
||||
minDiff = diff;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
var pair = cache[resolution] = [r, z];
|
||||
return pair;
|
||||
};
|
||||
})();
|
||||
|
||||
/**
|
||||
* Tiles rendered at the current resolution;
|
||||
* @type {Object}
|
||||
*/
|
||||
ol.renderer.TileLayerRenderer.prototype.renderedTiles_ = {};
|
||||
|
||||
/**
|
||||
* @param {Array.<number>} ijz
|
||||
* @return {Array.<number>}
|
||||
*/
|
||||
ol.renderer.TileLayerRenderer.prototype.getTileCoordsFromNormalizedCoords_ = function(ijz) {
|
||||
return [
|
||||
this.xRight_ ? ijz[0] : -ijz[0] - 1,
|
||||
this.yDown_ ? ijz[1] : -ijz[1] - 1,
|
||||
ijz[2]
|
||||
];
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {ol.Loc} center
|
||||
* @param {number} resolution
|
||||
* @return {goog.math.Box}
|
||||
*/
|
||||
ol.renderer.TileLayerRenderer.prototype.getTileBox_ = function(center, resolution) {
|
||||
var size = this.getContainerSize();
|
||||
var halfWidth = size.width / 2;
|
||||
var halfHeight = size.height / 2;
|
||||
|
||||
var leftTop = new ol.Loc(
|
||||
center.getX() - (resolution * halfWidth),
|
||||
center.getY() + (resolution * halfHeight));
|
||||
|
||||
var rightBottom = new ol.Loc(
|
||||
center.getX() + (resolution * halfWidth),
|
||||
center.getY() - (resolution * halfHeight));
|
||||
|
||||
var ltCoord = this.getNormalizedTileCoord_(leftTop, resolution);
|
||||
var rbCoord = this.getNormalizedTileCoord_(rightBottom, resolution);
|
||||
|
||||
// right and bottom are treated as excluded, so we increment for the box
|
||||
rbCoord.x += 1;
|
||||
rbCoord.y += 1;
|
||||
|
||||
return goog.math.Box.boundingBox(ltCoord, rbCoord);
|
||||
};
|
||||
|
||||
/**
|
||||
* Get rid of tiles outside the rendered extent.
|
||||
*/
|
||||
ol.renderer.TileLayerRenderer.prototype.removeInvisibleTiles_ = function() {
|
||||
var index, prune, x, y, z, tile;
|
||||
var xRight = (this.xRight_ > 0);
|
||||
var yDown = (this.yDown_ > 0);
|
||||
var top = this.renderedTop_;
|
||||
var right = this.renderedRight_;
|
||||
var bottom = this.renderedBottom_;
|
||||
var left = this.renderedLeft_;
|
||||
for (var xyz in this.renderedTiles_) {
|
||||
index = xyz.split(",");
|
||||
x = +index[0];
|
||||
y = +index[1];
|
||||
var index, prune, i, j, z, tile;
|
||||
var box = this.renderedTileBox_;
|
||||
for (var ijz in this.renderedTiles_) {
|
||||
index = ijz.split(",");
|
||||
i = +index[0];
|
||||
j = +index[1];
|
||||
z = +index[2];
|
||||
prune = this.renderedZ_ !== z ||
|
||||
// beyond on the left side
|
||||
(xRight ? x < left : x > left) ||
|
||||
// beyond on the right side
|
||||
(xRight ? x > right : x < right) ||
|
||||
// above
|
||||
(yDown ? y < top : y > top) ||
|
||||
// below
|
||||
(yDown ? y > bottom : y < bottom);
|
||||
i < box.left || // beyond on the left side
|
||||
i >= box.right || // beyond on the right side
|
||||
j < box.top || // above
|
||||
j >= box.bottom; // below
|
||||
if (prune) {
|
||||
tile = this.renderedTiles_[xyz];
|
||||
delete this.renderedTiles_[xyz];
|
||||
this.target_.removeChild(tile.getImg());
|
||||
tile = this.renderedTiles_[ijz];
|
||||
delete this.renderedTiles_[ijz];
|
||||
this.container_.removeChild(tile.getImg());
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -294,12 +306,14 @@ ol.renderer.TileLayerRenderer.prototype.removeInvisibleTiles_ = function() {
|
||||
* Deal with changes in resolution.
|
||||
* TODO: implement the animation
|
||||
*
|
||||
* @param {ol.Loc} center New center.
|
||||
* @param {number} resolution New resolution.
|
||||
*/
|
||||
ol.renderer.TileLayerRenderer.prototype.changeResolution_ = function(center, resolution) {
|
||||
ol.renderer.TileLayerRenderer.prototype.changeResolution_ = function(resolution) {
|
||||
var pair = this.getPreferredResAndZ_(resolution);
|
||||
this.renderedZ_ = pair[1];
|
||||
this.renderedResolution_ = resolution;
|
||||
this.renderedTiles_ = {};
|
||||
goog.dom.removeChildren(this.target_);
|
||||
goog.dom.removeChildren(this.container_);
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -172,10 +172,4 @@ describe("ol.event.Events", function() {
|
||||
expect(ol.event.isMultiTouch({})).toBe(false);
|
||||
});
|
||||
|
||||
it("provides an isEnterOrSpace() function", function() {
|
||||
expect(ol.event.isEnterOrSpace({type: 'keypress', keyCode: 13})).toBe(true);
|
||||
expect(ol.event.isEnterOrSpace({type: 'keypress', keyCode: 32})).toBe(true);
|
||||
expect(ol.event.isEnterOrSpace({type: 'keypress', keyCode: 3})).toBe(true);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
@@ -1935,12 +1935,12 @@
|
||||
map.destroy();
|
||||
}
|
||||
|
||||
function test_moveByPx(t) {
|
||||
function test_moveByViewportPx(t) {
|
||||
t.plan(16);
|
||||
|
||||
var moved;
|
||||
var Layer = OpenLayers.Class(OpenLayers.Layer, {
|
||||
moveByPx: function(dx, dy) {
|
||||
moveByViewportPx: function(dx, dy) {
|
||||
moved[this.name] = true;
|
||||
}
|
||||
});
|
||||
@@ -1972,7 +1972,7 @@
|
||||
|
||||
// move to a valid position
|
||||
moved = {};
|
||||
map.moveByPx(-455, 455);
|
||||
map.moveByViewportPx(-455, 455);
|
||||
t.eq(map.layerContainerDiv.style.left, '455px',
|
||||
'[valid position] layer container left correct');
|
||||
t.eq(map.layerContainerDiv.style.top, '-455px',
|
||||
@@ -1984,7 +1984,7 @@
|
||||
|
||||
// move outside the max extent
|
||||
moved = {};
|
||||
map.moveByPx(-4500, 4500);
|
||||
map.moveByViewportPx(-4500, 4500);
|
||||
t.eq(map.layerContainerDiv.style.left, '455px',
|
||||
'[outside max extent] layer container left correct');
|
||||
t.eq(map.layerContainerDiv.style.top, '-455px',
|
||||
@@ -1996,7 +1996,7 @@
|
||||
|
||||
// move outside the restricted extent
|
||||
moved = {};
|
||||
map.moveByPx(-500, 500);
|
||||
map.moveByViewportPx(-500, 500);
|
||||
t.eq(map.layerContainerDiv.style.left, '455px',
|
||||
'[outside restricted extent] layer container left correct');
|
||||
t.eq(map.layerContainerDiv.style.top, '-455px',
|
||||
@@ -2011,7 +2011,7 @@
|
||||
}
|
||||
|
||||
// test for http://trac.osgeo.org/openlayers/ticket/3388
|
||||
function test_moveByPx_restrictedExtent(t) {
|
||||
function test_moveByViewportPx_restrictedExtent(t) {
|
||||
t.plan(2);
|
||||
|
||||
var map = new OpenLayers.Map({
|
||||
@@ -2024,7 +2024,7 @@
|
||||
|
||||
map.zoomToExtent(new OpenLayers.Bounds(-11.25, 0, 11.25, 11.25));
|
||||
|
||||
map.moveByPx(-10, -10);
|
||||
map.moveByViewportPx(-10, -10);
|
||||
t.eq(map.layerContainerDiv.style.left, '10px', 'layer container left correct');
|
||||
t.eq(map.layerContainerDiv.style.top, '0px', 'layer container top correct');
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user