Merge pull request #3571 from ahocevar/vector-wrapx

Add wrapX support for vector layers (canvas renderer only)
This commit is contained in:
Andreas Hocevar
2015-04-22 09:21:02 +02:00
14 changed files with 341 additions and 74 deletions
@@ -127,7 +127,7 @@ ol.renderer.canvas.Layer.prototype.dispatchComposeEvent_ =
var layer = this.getLayer();
if (layer.hasListener(type)) {
var transform = goog.isDef(opt_transform) ?
opt_transform : this.getTransform(frameState);
opt_transform : this.getTransform(frameState, 0);
var render = new ol.render.canvas.Immediate(
context, frameState.pixelRatio, frameState.extent, transform,
frameState.viewState.rotation);
@@ -192,10 +192,12 @@ ol.renderer.canvas.Layer.prototype.getImageTransform = goog.abstractMethod;
/**
* @param {olx.FrameState} frameState Frame state.
* @param {number} offsetX Offset on the x-axis in view coordinates.
* @protected
* @return {!goog.vec.Mat4.Number} Transform.
*/
ol.renderer.canvas.Layer.prototype.getTransform = function(frameState) {
ol.renderer.canvas.Layer.prototype.getTransform =
function(frameState, offsetX) {
var viewState = frameState.viewState;
var pixelRatio = frameState.pixelRatio;
return ol.vec.Mat4.makeTransform2D(this.transform_,
@@ -204,7 +206,8 @@ ol.renderer.canvas.Layer.prototype.getTransform = function(frameState) {
pixelRatio / viewState.resolution,
-pixelRatio / viewState.resolution,
-viewState.rotation,
-viewState.center[0], -viewState.center[1]);
-viewState.center[0] + offsetX,
-viewState.center[1]);
};
+39 -18
View File
@@ -10,6 +10,7 @@ goog.require('ol');
goog.require('ol.RendererType');
goog.require('ol.css');
goog.require('ol.dom');
goog.require('ol.extent');
goog.require('ol.layer.Image');
goog.require('ol.layer.Layer');
goog.require('ol.layer.Tile');
@@ -102,29 +103,41 @@ ol.renderer.canvas.Map.prototype.dispatchComposeEvent_ =
var extent = frameState.extent;
var pixelRatio = frameState.pixelRatio;
var viewState = frameState.viewState;
var projection = viewState.projection;
var resolution = viewState.resolution;
var rotation = viewState.rotation;
ol.vec.Mat4.makeTransform2D(this.transform_,
this.canvas_.width / 2, this.canvas_.height / 2,
pixelRatio / resolution, -pixelRatio / resolution,
-rotation,
-viewState.center[0], -viewState.center[1]);
var offsetX = 0;
if (projection.canWrapX()) {
var projectionExtent = projection.getExtent();
var worldWidth = ol.extent.getWidth(projectionExtent);
var x = frameState.focus[0];
if (x < projectionExtent[0] || x > projectionExtent[2]) {
var worldsAway = Math.ceil((projectionExtent[0] - x) / worldWidth);
offsetX = worldWidth * worldsAway;
extent = [
extent[0] + offsetX, extent[1],
extent[2] + offsetX, extent[3]
];
}
}
var transform = this.getTransform(frameState, offsetX);
var tolerance = ol.renderer.vector.getTolerance(resolution, pixelRatio);
var replayGroup = new ol.render.canvas.ReplayGroup(tolerance, extent,
resolution);
var replayGroup = new ol.render.canvas.ReplayGroup(
tolerance, extent, resolution);
var vectorContext = new ol.render.canvas.Immediate(context, pixelRatio,
extent, this.transform_, rotation);
extent, transform, rotation);
var composeEvent = new ol.render.Event(type, map, vectorContext,
replayGroup, frameState, context, null);
map.dispatchEvent(composeEvent);
replayGroup.finish();
if (!replayGroup.isEmpty()) {
replayGroup.replay(context, pixelRatio, this.transform_,
rotation, {});
replayGroup.replay(context, pixelRatio, transform, rotation, {});
}
vectorContext.flush();
this.replayGroup = replayGroup;
@@ -133,14 +146,21 @@ ol.renderer.canvas.Map.prototype.dispatchComposeEvent_ =
/**
* @param {ol.layer.Layer} layer Layer.
* @return {ol.renderer.canvas.Layer} Canvas layer renderer.
* @param {olx.FrameState} frameState Frame state.
* @param {number} offsetX Offset on the x-axis in view coordinates.
* @protected
* @return {!goog.vec.Mat4.Number} Transform.
*/
ol.renderer.canvas.Map.prototype.getCanvasLayerRenderer = function(layer) {
var layerRenderer = this.getLayerRenderer(layer);
goog.asserts.assertInstanceof(layerRenderer, ol.renderer.canvas.Layer,
'layerRenderer is an instance of ol.renderer.canvas.Layer');
return /** @type {ol.renderer.canvas.Layer} */ (layerRenderer);
ol.renderer.canvas.Map.prototype.getTransform = function(frameState, offsetX) {
var pixelRatio = frameState.pixelRatio;
var viewState = frameState.viewState;
var resolution = viewState.resolution;
return ol.vec.Mat4.makeTransform2D(this.transform_,
this.canvas_.width / 2, this.canvas_.height / 2,
pixelRatio / resolution, -pixelRatio / resolution,
-viewState.rotation,
-viewState.center[0] - offsetX,
-viewState.center[1]);
};
@@ -197,7 +217,8 @@ ol.renderer.canvas.Map.prototype.renderFrame = function(frameState) {
}
}
this.dispatchComposeEvent_(ol.render.EventType.POSTCOMPOSE, frameState);
this.dispatchComposeEvent_(
ol.render.EventType.POSTCOMPOSE, frameState);
if (!this.renderedVisible_) {
goog.style.setElementShown(this.canvas_, true);
@@ -11,6 +11,7 @@ goog.require('ol.render.EventType');
goog.require('ol.render.canvas.ReplayGroup');
goog.require('ol.renderer.canvas.Layer');
goog.require('ol.renderer.vector');
goog.require('ol.source.Vector');
@@ -75,7 +76,18 @@ goog.inherits(ol.renderer.canvas.VectorLayer, ol.renderer.canvas.Layer);
ol.renderer.canvas.VectorLayer.prototype.composeFrame =
function(frameState, layerState, context) {
var transform = this.getTransform(frameState);
var extent = frameState.extent;
var focus = frameState.focus;
var pixelRatio = frameState.pixelRatio;
var skippedFeatureUids = frameState.skippedFeatureUids;
var viewState = frameState.viewState;
var projection = viewState.projection;
var rotation = viewState.rotation;
var projectionExtent = projection.getExtent();
var vectorSource = this.getLayer().getSource();
goog.asserts.assertInstanceof(vectorSource, ol.source.Vector);
var transform = this.getTransform(frameState, 0);
this.dispatchPreComposeEvent(context, frameState, transform);
@@ -96,9 +108,48 @@ ol.renderer.canvas.VectorLayer.prototype.composeFrame =
// see http://jsperf.com/context-save-restore-versus-variable
var alpha = replayContext.globalAlpha;
replayContext.globalAlpha = layerState.opacity;
replayGroup.replay(
replayContext, frameState.pixelRatio, transform,
frameState.viewState.rotation, frameState.skippedFeatureUids);
var noSkip = {};
var focusX = focus[0];
if (vectorSource.getWrapX() && projection.canWrapX() &&
!ol.extent.containsExtent(projectionExtent, extent)) {
var projLeft = projectionExtent[0];
var projRight = projectionExtent[2];
// A feature from skippedFeatureUids will only be skipped in the world
// that has the frameState's focus, because this is where a feature
// overlay for highlighting or selection would render the skipped
// feature.
replayGroup.replay(replayContext, pixelRatio, transform, rotation,
projLeft <= focusX && focusX <= projRight ?
skippedFeatureUids : noSkip);
var startX = extent[0];
var worldWidth = ol.extent.getWidth(projectionExtent);
var world = 0;
var offsetX;
while (startX < projectionExtent[0]) {
--world;
offsetX = worldWidth * world;
transform = this.getTransform(frameState, offsetX);
replayGroup.replay(replayContext, pixelRatio, transform, rotation,
projLeft + offsetX <= focusX && focusX <= projRight + offsetX ?
skippedFeatureUids : noSkip);
startX += worldWidth;
}
world = 0;
startX = extent[2];
while (startX > projectionExtent[2]) {
++world;
offsetX = worldWidth * world;
transform = this.getTransform(frameState, offsetX);
replayGroup.replay(replayContext, pixelRatio, transform, rotation,
projLeft + offsetX <= focusX && focusX <= projRight + offsetX ?
skippedFeatureUids : noSkip);
startX -= worldWidth;
}
} else {
replayGroup.replay(
replayContext, pixelRatio, transform, rotation, skippedFeatureUids);
}
if (replayContext != context) {
this.dispatchRenderEvent(replayContext, frameState, transform);
@@ -194,6 +245,14 @@ ol.renderer.canvas.VectorLayer.prototype.prepareFrame =
var extent = ol.extent.buffer(frameStateExtent,
vectorLayerRenderBuffer * resolution);
var projectionExtent = viewState.projection.getExtent();
if (vectorSource.getWrapX() && viewState.projection.canWrapX() &&
!ol.extent.containsExtent(projectionExtent, frameState.extent)) {
// do not clip when the view crosses the -180° or 180° meridians
extent[0] = projectionExtent[0];
extent[2] = projectionExtent[2];
}
if (!this.dirty_ &&
this.renderedResolution_ == resolution &&
+36 -17
View File
@@ -9,6 +9,7 @@ goog.require('goog.events.EventType');
goog.require('goog.functions');
goog.require('goog.object');
goog.require('goog.vec.Mat4');
goog.require('ol.extent');
goog.require('ol.layer.Layer');
goog.require('ol.renderer.Layer');
goog.require('ol.style.IconImageCache');
@@ -40,6 +41,7 @@ ol.renderer.Map = function(container, map) {
goog.base(this);
/**
* @private
* @type {ol.Map}
@@ -136,23 +138,39 @@ ol.renderer.Map.prototype.forEachFeatureAtCoordinate =
var viewState = frameState.viewState;
var viewResolution = viewState.resolution;
var viewRotation = viewState.rotation;
/** @type {Object.<string, boolean>} */
var features = {};
/**
* @param {ol.Feature} feature Feature.
* @return {?} Callback result.
*/
function forEachFeatureAtCoordinate(feature) {
goog.asserts.assert(goog.isDef(feature), 'received a feature');
var key = goog.getUid(feature).toString();
if (!(key in features)) {
features[key] = true;
return callback.call(thisArg, feature, null);
}
}
var projection = viewState.projection;
var translatedCoordinate = coordinate;
if (projection.canWrapX()) {
var projectionExtent = projection.getExtent();
var worldWidth = ol.extent.getWidth(projectionExtent);
var x = coordinate[0];
if (x < projectionExtent[0] || x > projectionExtent[2]) {
var worldsAway = Math.ceil((projectionExtent[0] - x) / worldWidth);
translatedCoordinate = [x + worldWidth * worldsAway, coordinate[1]];
}
}
if (!goog.isNull(this.replayGroup)) {
/** @type {Object.<string, boolean>} */
var features = {};
result = this.replayGroup.forEachFeatureAtCoordinate(coordinate,
viewResolution, viewRotation, {},
/**
* @param {ol.Feature} feature Feature.
* @return {?} Callback result.
*/
function(feature) {
goog.asserts.assert(goog.isDef(feature), 'received a feature');
var key = goog.getUid(feature).toString();
if (!(key in features)) {
features[key] = true;
return callback.call(thisArg, feature, null);
}
});
result = this.replayGroup.forEachFeatureAtCoordinate(translatedCoordinate,
viewResolution, viewRotation, {}, forEachFeatureAtCoordinate);
if (result) {
return result;
}
@@ -167,7 +185,8 @@ ol.renderer.Map.prototype.forEachFeatureAtCoordinate =
layerFilter.call(thisArg2, layer)) {
var layerRenderer = this.getLayerRenderer(layer);
result = layerRenderer.forEachFeatureAtCoordinate(
coordinate, frameState, callback, thisArg);
layer.getSource().getWrapX() ? translatedCoordinate : coordinate,
frameState, callback, thisArg);
if (result) {
return result;
}