Compare commits

..

11 Commits

Author SHA1 Message Date
ahocevar
2eea8df75a Update package version to 4.6.5 2018-03-18 23:33:43 +01:00
ahocevar
c3870aed81 Changelog for v4.6.5 2018-03-18 23:32:50 +01:00
ahocevar
98d0fc05c8 Backport types 2018-03-18 23:20:32 +01:00
Andreas Hocevar
2912a5d7a7 Merge pull request #7669 from ahocevar/hit-detect-declutter
Use declutter tree only for text and image replays
2018-03-18 22:45:40 +01:00
Andreas Hocevar
72ca7b28c6 Update package version to 4.6.4 2017-12-11 11:31:38 +01:00
Andreas Hocevar
f11d55fde6 Changelog for v4.6.4 2017-12-11 11:29:50 +01:00
Andreas Hocevar
48217bc218 Handle skipping and unskipping features with renderMode: 'image' 2017-12-11 11:23:34 +01:00
Andreas Hocevar
c76c445e43 Update package version to 4.6.3 2017-12-08 11:17:36 +01:00
Andreas Hocevar
3bba8ef061 Changelog for v4.6.3 2017-12-08 11:16:52 +01:00
Andreas Hocevar
a699cc348b Fix pull request link 2017-12-08 11:14:24 +01:00
Andreas Hocevar
f010f7b9c1 Only compose image vector frame when the replay group has changed 2017-12-08 11:12:05 +01:00
14 changed files with 136 additions and 69 deletions

View File

@@ -4,4 +4,4 @@ The v4.6.2 release fixes a regression that could cause tremendous amounts of unn
## Fixes
* [#7546](Do not request features for wrapped extent) - Do not request features for wrapped extent ([@ahocevar](https://github.com/ahocevar))
* [#7546](https://github.com/openlayers/openlayers/pull/7546) - Do not request features for wrapped extent ([@ahocevar](https://github.com/ahocevar))

7
changelog/v4.6.3.md Normal file
View File

@@ -0,0 +1,7 @@
# 4.6.3
The v4.6.3 release fixes a performance issue when `renderMode: 'image'` is set on an `ol.layer.Vector`.
## Fixes
* [#7554](https://github.com/openlayers/openlayers/pull/7554) - Only compose image vector frame when the replay group has changed ([@ahocevar](https://github.com/ahocevar))

7
changelog/v4.6.4.md Normal file
View File

@@ -0,0 +1,7 @@
# 4.6.4
The v4.6.4 release fixes a feature selection issue when `renderMode: 'image'` is set on an `ol.layer.Vector`.
## Fixes
* [#7559](https://github.com/openlayers/openlayers/pull/7559) - Handle skipping and unskipping features with renderMode: 'image' ([@ahocevar](https://github.com/ahocevar))

7
changelog/v4.6.5.md Normal file
View File

@@ -0,0 +1,7 @@
# 4.6.5
The v4.6.5 release fixes a hit detection issue when `declutter: true` is set on an `ol.layer.VectorTile`.
## Fixes
* [#7669](https://github.com/openlayers/openlayers/pull/7559) - Use declutter tree only for text and image replays ([@ahocevar](https://github.com/ahocevar))

View File

@@ -8525,7 +8525,7 @@ olx.view.FitOptions.prototype.callback;
* pixelToCoordinateTransform: ol.Transform,
* postRenderFunctions: Array.<ol.PostRenderFunction>,
* size: ol.Size,
* skippedFeatureUids: Object.<string, boolean>,
* skippedFeatureUids: !Object.<string, boolean>,
* tileQueue: ol.TileQueue,
* time: number,
* usedTiles: Object.<string, Object.<string, ol.TileRange>>,

View File

@@ -1,6 +1,6 @@
{
"name": "openlayers",
"version": "4.6.2",
"version": "4.6.5",
"description": "Build tools and sources for developing OpenLayers based mapping applications",
"keywords": [
"map",

View File

@@ -1,6 +1,6 @@
{
"name": "ol",
"version": "4.6.2",
"version": "4.6.5",
"description": "OpenLayers as ES2015 modules",
"main": "index.js",
"module": "index.js",

View File

@@ -321,18 +321,21 @@ ol.render.canvas.ReplayGroup.prototype.forEachFeatureAtCoordinate = function(
});
}
var replayType;
/**
* @param {ol.Feature|ol.render.Feature} feature Feature.
* @return {?} Callback result.
*/
function hitDetectionCallback(feature) {
function featureCallback(feature) {
var imageData = context.getImageData(0, 0, contextSize, contextSize).data;
for (var i = 0; i < contextSize; i++) {
for (var j = 0; j < contextSize; j++) {
if (mask[i][j]) {
if (imageData[(j * contextSize + i) * 4 + 3] > 0) {
var result;
if (!declutteredFeatures || declutteredFeatures.indexOf(feature) !== -1) {
if (!(declutteredFeatures && (replayType == ol.render.ReplayType.IMAGE || replayType == ol.render.ReplayType.TEXT)) ||
declutteredFeatures.indexOf(feature) !== -1) {
result = callback(feature);
}
if (result) {
@@ -347,8 +350,37 @@ ol.render.canvas.ReplayGroup.prototype.forEachFeatureAtCoordinate = function(
}
}
return this.replayHitDetection_(context, transform, rotation,
skippedFeaturesHash, hitDetectionCallback, hitExtent, declutterReplays);
/** @type {Array.<number>} */
var zs = Object.keys(this.replaysByZIndex_).map(Number);
zs.sort(ol.array.numberSafeCompareFunction);
var i, j, replays, replay, result;
for (i = zs.length - 1; i >= 0; --i) {
var zIndexKey = zs[i].toString();
replays = this.replaysByZIndex_[zIndexKey];
for (j = ol.render.replay.ORDER.length - 1; j >= 0; --j) {
replayType = ol.render.replay.ORDER[j];
replay = replays[replayType];
if (replay !== undefined) {
if (declutterReplays &&
(replayType == ol.render.ReplayType.IMAGE || replayType == ol.render.ReplayType.TEXT)) {
var declutter = declutterReplays[zIndexKey];
if (!declutter) {
declutterReplays[zIndexKey] = [replay, transform.slice(0)];
} else {
declutter.push(replay, transform.slice(0));
}
} else {
result = replay.replayHitDetection(context, transform, rotation,
skippedFeaturesHash, featureCallback, hitExtent);
if (result) {
return result;
}
}
}
}
}
return undefined;
};
@@ -457,59 +489,6 @@ ol.render.canvas.ReplayGroup.prototype.replay = function(context,
};
/**
* @private
* @param {CanvasRenderingContext2D} context Context.
* @param {ol.Transform} transform Transform.
* @param {number} viewRotation View rotation.
* @param {Object.<string, boolean>} skippedFeaturesHash Ids of features
* to skip.
* @param {function((ol.Feature|ol.render.Feature)): T} featureCallback
* Feature callback.
* @param {ol.Extent=} opt_hitExtent Only check features that intersect this
* extent.
* @param {Object.<string, ol.DeclutterGroup>=} opt_declutterReplays Declutter
* replays.
* @return {T|undefined} Callback result.
* @template T
*/
ol.render.canvas.ReplayGroup.prototype.replayHitDetection_ = function(
context, transform, viewRotation, skippedFeaturesHash,
featureCallback, opt_hitExtent, opt_declutterReplays) {
/** @type {Array.<number>} */
var zs = Object.keys(this.replaysByZIndex_).map(Number);
zs.sort(ol.array.numberSafeCompareFunction);
var i, j, replays, replay, result;
for (i = zs.length - 1; i >= 0; --i) {
var zIndexKey = zs[i].toString();
replays = this.replaysByZIndex_[zIndexKey];
for (j = ol.render.replay.ORDER.length - 1; j >= 0; --j) {
var replayType = ol.render.replay.ORDER[j];
replay = replays[replayType];
if (replay !== undefined) {
if (opt_declutterReplays &&
(replayType == ol.render.ReplayType.IMAGE || replayType == ol.render.ReplayType.TEXT)) {
var declutter = opt_declutterReplays[zIndexKey];
if (!declutter) {
opt_declutterReplays[zIndexKey] = [replay, transform.slice(0)];
} else {
declutter.push(replay, transform.slice(0));
}
} else {
result = replay.replayHitDetection(context, transform, viewRotation,
skippedFeaturesHash, featureCallback, opt_hitExtent);
if (result) {
return result;
}
}
}
}
}
return undefined;
};
/**
* @const
* @private

View File

@@ -4,6 +4,7 @@ goog.require('ol');
goog.require('ol.ImageCanvas');
goog.require('ol.LayerType');
goog.require('ol.ViewHint');
goog.require('ol.array');
goog.require('ol.extent');
goog.require('ol.layer.VectorRenderType');
goog.require('ol.obj');
@@ -35,6 +36,11 @@ ol.renderer.canvas.ImageLayer = function(imageLayer) {
*/
this.imageTransform_ = ol.transform.create();
/**
* @type {!Array.<string>}
*/
this.skippedFeatures_ = [];
/**
* @private
* @type {ol.renderer.canvas.VectorLayer}
@@ -127,8 +133,9 @@ ol.renderer.canvas.ImageLayer.prototype.prepareFrame = function(frameState, laye
projection = sourceProjection;
}
}
if (this.vectorRenderer_) {
var context = this.vectorRenderer_.context;
var vectorRenderer = this.vectorRenderer_;
if (vectorRenderer) {
var context = vectorRenderer.context;
var imageFrameState = /** @type {olx.FrameState} */ (ol.obj.assign({}, frameState, {
size: [
ol.extent.getWidth(renderedExtent) / viewResolution,
@@ -138,12 +145,16 @@ ol.renderer.canvas.ImageLayer.prototype.prepareFrame = function(frameState, laye
rotation: 0
}))
}));
if (this.vectorRenderer_.prepareFrame(imageFrameState, layerState)) {
var skippedFeatures = Object.keys(imageFrameState.skippedFeatureUids).sort();
if (vectorRenderer.prepareFrame(imageFrameState, layerState) &&
(vectorRenderer.replayGroupChanged ||
!ol.array.equals(skippedFeatures, this.skippedFeatures_))) {
context.canvas.width = imageFrameState.size[0] * pixelRatio;
context.canvas.height = imageFrameState.size[1] * pixelRatio;
this.vectorRenderer_.composeFrame(imageFrameState, layerState, context);
vectorRenderer.composeFrame(imageFrameState, layerState, context);
this.image_ = new ol.ImageCanvas(renderedExtent, viewResolution, pixelRatio, context.canvas);
this.skippedFeatures_ = skippedFeatures;
}
this.image_ = new ol.ImageCanvas(renderedExtent, viewResolution, pixelRatio, context.canvas);
} else {
image = imageSource.getImage(
renderedExtent, viewResolution, pixelRatio, projection);

View File

@@ -69,6 +69,12 @@ ol.renderer.canvas.VectorLayer = function(vectorLayer) {
*/
this.replayGroup_ = null;
/**
* A new replay group had to be created by `prepareFrame()`
* @type {boolean}
*/
this.replayGroupChanged = true;
/**
* @type {CanvasRenderingContext2D}
*/
@@ -343,6 +349,7 @@ ol.renderer.canvas.VectorLayer.prototype.prepareFrame = function(frameState, lay
this.renderedRevision_ == vectorLayerRevision &&
this.renderedRenderOrder_ == vectorLayerRenderOrder &&
ol.extent.containsExtent(this.renderedExtent_, extent)) {
this.replayGroupChanged = false;
return true;
}
@@ -400,6 +407,7 @@ ol.renderer.canvas.VectorLayer.prototype.prepareFrame = function(frameState, lay
this.renderedExtent_ = extent;
this.replayGroup_ = replayGroup;
this.replayGroupChanged = true;
return true;
};

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@@ -248,6 +248,32 @@ describe('ol.rendering.layer.Vector', function() {
});
});
it('unskips features correctly with renderMode: \'image\'', function(done) {
createMap('canvas');
addCircle(500);
addPolygon(300);
map.skipFeature(source.getFeatures()[1]);
map.addLayer(new ol.layer.Vector({
renderMode: 'image',
source: source,
style: new ol.style.Style({
fill: new ol.style.Fill({
color: 'rgba(255,0,0,0.5)'
}),
stroke: new ol.style.Stroke({
width: 2,
color: 'black'
})
})
}));
map.renderSync();
map.unskipFeature(source.getFeatures()[1]);
map.once('postrender', function() {
expectResemble(map, 'rendering/ol/layer/expected/vector.png',
IMAGE_TOLERANCE, done);
});
});
it('renders fill/stroke batches correctly with the canvas renderer', function(done) {
createMap('canvas');
source = new ol.source.Vector({

View File

@@ -5,7 +5,7 @@ goog.require('ol.Map');
goog.require('ol.MapEvent');
goog.require('ol.Overlay');
goog.require('ol.View');
goog.require('ol.geom.Point');
goog.require('ol.geom.LineString');
goog.require('ol.has');
goog.require('ol.interaction');
goog.require('ol.interaction.DoubleClickZoom');
@@ -199,12 +199,12 @@ describe('ol.Map', function() {
target: target,
layers: [new ol.layer.Vector({
source: new ol.source.Vector({
features: [new ol.Feature(new ol.geom.Point([0, 0]))]
features: [new ol.Feature(new ol.geom.LineString([[-50, 0], [50, 0]]))]
})
})],
view: new ol.View({
center: [0, 0],
zoom: 2
zoom: 17
})
});
map.renderSync();
@@ -224,6 +224,20 @@ describe('ol.Map', function() {
expect(features[0]).to.be.an(ol.Feature);
});
it('returns an array of found features with declutter: true', function() {
var layer = map.getLayers().item(0);
map.removeLayer(layer);
var otherLayer = new ol.layer.Vector({
declutter: true,
source: layer.getSource()
});
map.addLayer(otherLayer);
map.renderSync();
var features = map.getFeaturesAtPixel([50, 50]);
expect(features).to.be.an(Array);
expect(features[0]).to.be.an(ol.Feature);
});
it('respects options', function() {
var otherLayer = new ol.layer.Vector({
source: new ol.source.Vector

View File

@@ -290,6 +290,14 @@ describe('ol.renderer.canvas.VectorLayer', function() {
], buffer));
});
it('sets replayGroupChanged correctly', function() {
frameState.extent = [-10000, -10000, 10000, 10000];
renderer.prepareFrame(frameState, {});
expect(renderer.replayGroupChanged).to.be(true);
renderer.prepareFrame(frameState, {});
expect(renderer.replayGroupChanged).to.be(false);
});
});
});