Introduce new overlaps option for Vector and VectorTile sources
Instead of deciding whether to batch fills and strokes by looking at the opacity of the style, we now rely on user input.
This commit is contained in:
@@ -93,6 +93,7 @@ var map = new ol.Map({
|
||||
new ol.layer.VectorTile({
|
||||
source: new ol.source.VectorTile({
|
||||
format: format,
|
||||
overlaps: false,
|
||||
tileGrid: tileGrid,
|
||||
url: 'http://{a-c}.tile.openstreetmap.us/' +
|
||||
'vectiles-land-usages/{z}/{x}/{y}.topojson'
|
||||
|
||||
@@ -29,7 +29,8 @@ var style = new ol.style.Style({
|
||||
var vector = new ol.layer.Vector({
|
||||
source: new ol.source.Vector({
|
||||
url: 'data/topojson/world-110m.json',
|
||||
format: new ol.format.TopoJSON()
|
||||
format: new ol.format.TopoJSON(),
|
||||
overlaps: false
|
||||
}),
|
||||
style: function(feature) {
|
||||
// don't want to render the full world polygon, which repeats all countries
|
||||
|
||||
@@ -4366,6 +4366,7 @@ olx.source.TileImageOptions.prototype.wrapX;
|
||||
* cacheSize: (number|undefined),
|
||||
* format: (ol.format.Feature|undefined),
|
||||
* logo: (string|olx.LogoOptions|undefined),
|
||||
* overlaps: (boolean|undefined),
|
||||
* projection: ol.ProjectionLike,
|
||||
* state: (ol.source.State|undefined),
|
||||
* tileClass: (function(new: ol.VectorTile, ol.TileCoord,
|
||||
@@ -4415,6 +4416,17 @@ olx.source.VectorTileOptions.prototype.format;
|
||||
olx.source.VectorTileOptions.prototype.logo;
|
||||
|
||||
|
||||
/**
|
||||
* This source may have overlapping geometries. Default is `true`. Setting this
|
||||
* to `false` (e.g. for sources with polygons that represent adminstrative
|
||||
* boundaries or TopoJSON sources) allows the renderer to optimise fill and
|
||||
* stroke operations.
|
||||
* @type {boolean|undefined}
|
||||
* @api
|
||||
*/
|
||||
olx.source.VectorTileOptions.prototype.overlaps;
|
||||
|
||||
|
||||
/**
|
||||
* Projection.
|
||||
* @type {ol.ProjectionLike}
|
||||
@@ -5797,6 +5809,7 @@ olx.source.TileWMSOptions.prototype.wrapX;
|
||||
* format: (ol.format.Feature|undefined),
|
||||
* loader: (ol.FeatureLoader|undefined),
|
||||
* logo: (string|olx.LogoOptions|undefined),
|
||||
* overlaps: (boolean|undefined),
|
||||
* strategy: (ol.LoadingStrategy|undefined),
|
||||
* url: (string|ol.FeatureUrlFunction|undefined),
|
||||
* useSpatialIndex: (boolean|undefined),
|
||||
@@ -5849,6 +5862,17 @@ olx.source.VectorOptions.prototype.loader;
|
||||
olx.source.VectorOptions.prototype.logo;
|
||||
|
||||
|
||||
/**
|
||||
* This source may have overlapping geometries. Default is `true`. Setting this
|
||||
* to `false` (e.g. for sources with polygons that represent adminstrative
|
||||
* boundaries or TopoJSON sources) allows the renderer to optimise fill and
|
||||
* stroke operations.
|
||||
* @type {boolean|undefined}
|
||||
* @api
|
||||
*/
|
||||
olx.source.VectorOptions.prototype.overlaps;
|
||||
|
||||
|
||||
/**
|
||||
* The loading strategy to use. By default an {@link ol.loadingstrategy.all}
|
||||
* strategy is used, a one-off strategy which loads all features at once.
|
||||
|
||||
@@ -190,16 +190,6 @@ ol.color.fromStringInternal_ = function(s) {
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {ol.ColorLike|string} color Color.
|
||||
* @return {boolean} Is rgba.
|
||||
*/
|
||||
ol.color.isRgba = function(color) {
|
||||
return Array.isArray(color) && color.length == 4 ||
|
||||
typeof color == 'string' && ol.color.rgbaColorRe_.test(color);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {ol.Color} color Color.
|
||||
* @return {boolean} Is valid.
|
||||
|
||||
@@ -52,10 +52,11 @@ ol.render.canvas.Instruction = {
|
||||
* @param {number} tolerance Tolerance.
|
||||
* @param {ol.Extent} maxExtent Maximum extent.
|
||||
* @param {number} resolution Resolution.
|
||||
* @param {boolean} overlaps The replay can have overlapping geometries.
|
||||
* @protected
|
||||
* @struct
|
||||
*/
|
||||
ol.render.canvas.Replay = function(tolerance, maxExtent, resolution) {
|
||||
ol.render.canvas.Replay = function(tolerance, maxExtent, resolution, overlaps) {
|
||||
ol.render.VectorContext.call(this);
|
||||
|
||||
/**
|
||||
@@ -75,7 +76,7 @@ ol.render.canvas.Replay = function(tolerance, maxExtent, resolution) {
|
||||
* @protected
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.transparency = false;
|
||||
this.overlaps = overlaps;
|
||||
|
||||
/**
|
||||
* @private
|
||||
@@ -266,7 +267,7 @@ ol.render.canvas.Replay.prototype.replay_ = function(
|
||||
var pendingFill = 0;
|
||||
var pendingStroke = 0;
|
||||
var batchSize =
|
||||
this.instructions != instructions || this.transparency ? 0 : 200;
|
||||
this.instructions != instructions || this.overlaps ? 0 : 200;
|
||||
while (i < ii) {
|
||||
var instruction = instructions[i];
|
||||
var type = /** @type {ol.render.canvas.Instruction} */ (instruction[0]);
|
||||
@@ -691,11 +692,12 @@ ol.render.canvas.Replay.prototype.getBufferedMaxExtent = function() {
|
||||
* @param {number} tolerance Tolerance.
|
||||
* @param {ol.Extent} maxExtent Maximum extent.
|
||||
* @param {number} resolution Resolution.
|
||||
* @param {boolean} overlaps The replay can have overlapping geometries.
|
||||
* @protected
|
||||
* @struct
|
||||
*/
|
||||
ol.render.canvas.ImageReplay = function(tolerance, maxExtent, resolution) {
|
||||
ol.render.canvas.Replay.call(this, tolerance, maxExtent, resolution);
|
||||
ol.render.canvas.ImageReplay = function(tolerance, maxExtent, resolution, overlaps) {
|
||||
ol.render.canvas.Replay.call(this, tolerance, maxExtent, resolution, overlaps);
|
||||
|
||||
/**
|
||||
* @private
|
||||
@@ -957,12 +959,13 @@ ol.render.canvas.ImageReplay.prototype.setImageStyle = function(imageStyle) {
|
||||
* @param {number} tolerance Tolerance.
|
||||
* @param {ol.Extent} maxExtent Maximum extent.
|
||||
* @param {number} resolution Resolution.
|
||||
* @param {boolean} overlaps The replay can have overlapping geometries.
|
||||
* @protected
|
||||
* @struct
|
||||
*/
|
||||
ol.render.canvas.LineStringReplay = function(tolerance, maxExtent, resolution) {
|
||||
ol.render.canvas.LineStringReplay = function(tolerance, maxExtent, resolution, overlaps) {
|
||||
|
||||
ol.render.canvas.Replay.call(this, tolerance, maxExtent, resolution);
|
||||
ol.render.canvas.Replay.call(this, tolerance, maxExtent, resolution, overlaps);
|
||||
|
||||
/**
|
||||
* @private
|
||||
@@ -1191,12 +1194,13 @@ ol.render.canvas.LineStringReplay.prototype.setFillStrokeStyle = function(fillSt
|
||||
* @param {number} tolerance Tolerance.
|
||||
* @param {ol.Extent} maxExtent Maximum extent.
|
||||
* @param {number} resolution Resolution.
|
||||
* @param {boolean} overlaps The replay can have overlapping geometries.
|
||||
* @protected
|
||||
* @struct
|
||||
*/
|
||||
ol.render.canvas.PolygonReplay = function(tolerance, maxExtent, resolution) {
|
||||
ol.render.canvas.PolygonReplay = function(tolerance, maxExtent, resolution, overlaps) {
|
||||
|
||||
ol.render.canvas.Replay.call(this, tolerance, maxExtent, resolution);
|
||||
ol.render.canvas.Replay.call(this, tolerance, maxExtent, resolution, overlaps);
|
||||
|
||||
/**
|
||||
* @private
|
||||
@@ -1457,10 +1461,6 @@ ol.render.canvas.PolygonReplay.prototype.setFillStrokeStyle = function(fillStyle
|
||||
var fillStyleColor = fillStyle.getColor();
|
||||
state.fillStyle = ol.colorlike.asColorLike(fillStyleColor ?
|
||||
fillStyleColor : ol.render.canvas.defaultFillStyle);
|
||||
if (!this.transparency && ol.color.isRgba(state.fillStyle)) {
|
||||
this.transparency = ol.color.asArray(
|
||||
/** @type {ol.Color|string} */ (state.fillStyle))[0] != 1;
|
||||
}
|
||||
} else {
|
||||
state.fillStyle = undefined;
|
||||
}
|
||||
@@ -1468,9 +1468,6 @@ ol.render.canvas.PolygonReplay.prototype.setFillStrokeStyle = function(fillStyle
|
||||
var strokeStyleColor = strokeStyle.getColor();
|
||||
state.strokeStyle = ol.color.asString(strokeStyleColor ?
|
||||
strokeStyleColor : ol.render.canvas.defaultStrokeStyle);
|
||||
if (!this.transparency && ol.color.isRgba(state.strokeStyle)) {
|
||||
this.transparency = ol.color.asArray(state.strokeStyle)[3] != 1;
|
||||
}
|
||||
var strokeStyleLineCap = strokeStyle.getLineCap();
|
||||
state.lineCap = strokeStyleLineCap !== undefined ?
|
||||
strokeStyleLineCap : ol.render.canvas.defaultLineCap;
|
||||
@@ -1553,12 +1550,13 @@ ol.render.canvas.PolygonReplay.prototype.setFillStrokeStyles_ = function() {
|
||||
* @param {number} tolerance Tolerance.
|
||||
* @param {ol.Extent} maxExtent Maximum extent.
|
||||
* @param {number} resolution Resolution.
|
||||
* @param {boolean} overlaps The replay can have overlapping geometries.
|
||||
* @protected
|
||||
* @struct
|
||||
*/
|
||||
ol.render.canvas.TextReplay = function(tolerance, maxExtent, resolution) {
|
||||
ol.render.canvas.TextReplay = function(tolerance, maxExtent, resolution, overlaps) {
|
||||
|
||||
ol.render.canvas.Replay.call(this, tolerance, maxExtent, resolution);
|
||||
ol.render.canvas.Replay.call(this, tolerance, maxExtent, resolution, overlaps);
|
||||
|
||||
/**
|
||||
* @private
|
||||
@@ -1862,10 +1860,12 @@ ol.render.canvas.TextReplay.prototype.setTextStyle = function(textStyle) {
|
||||
* @param {number} tolerance Tolerance.
|
||||
* @param {ol.Extent} maxExtent Max extent.
|
||||
* @param {number} resolution Resolution.
|
||||
* @param {boolean} overlaps The replay group can have overlapping geometries.
|
||||
* @param {number=} opt_renderBuffer Optional rendering buffer.
|
||||
* @struct
|
||||
*/
|
||||
ol.render.canvas.ReplayGroup = function(tolerance, maxExtent, resolution, opt_renderBuffer) {
|
||||
ol.render.canvas.ReplayGroup = function(
|
||||
tolerance, maxExtent, resolution, overlaps, opt_renderBuffer) {
|
||||
ol.render.ReplayGroup.call(this);
|
||||
|
||||
/**
|
||||
@@ -1880,6 +1880,12 @@ ol.render.canvas.ReplayGroup = function(tolerance, maxExtent, resolution, opt_re
|
||||
*/
|
||||
this.maxExtent_ = maxExtent;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.overlaps_ = overlaps;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {number}
|
||||
@@ -1999,7 +2005,7 @@ ol.render.canvas.ReplayGroup.prototype.getReplay = function(zIndex, replayType)
|
||||
replayType +
|
||||
' constructor missing from ol.render.canvas.BATCH_CONSTRUCTORS_');
|
||||
replay = new Constructor(this.tolerance_, this.maxExtent_,
|
||||
this.resolution_);
|
||||
this.resolution_, this.overlaps_);
|
||||
replays[replayType] = replay;
|
||||
}
|
||||
return replay;
|
||||
@@ -2113,7 +2119,7 @@ ol.render.canvas.ReplayGroup.prototype.replayHitDetection_ = function(
|
||||
* @private
|
||||
* @type {Object.<ol.render.ReplayType,
|
||||
* function(new: ol.render.canvas.Replay, number, ol.Extent,
|
||||
* number)>}
|
||||
* number, boolean)>}
|
||||
*/
|
||||
ol.render.canvas.BATCH_CONSTRUCTORS_ = {
|
||||
'Image': ol.render.canvas.ImageReplay,
|
||||
|
||||
@@ -271,7 +271,7 @@ ol.renderer.canvas.VectorLayer.prototype.prepareFrame = function(frameState, lay
|
||||
var replayGroup =
|
||||
new ol.render.canvas.ReplayGroup(
|
||||
ol.renderer.vector.getTolerance(resolution, pixelRatio), extent,
|
||||
resolution, vectorLayer.getRenderBuffer());
|
||||
resolution, vectorSource.getOverlaps(), vectorLayer.getRenderBuffer());
|
||||
vectorSource.loadFeatures(extent, resolution, projection);
|
||||
/**
|
||||
* @param {ol.Feature} feature Feature.
|
||||
|
||||
@@ -207,7 +207,7 @@ ol.renderer.canvas.VectorTileLayer.prototype.createReplayGroup = function(tile,
|
||||
}
|
||||
replayState.dirty = false;
|
||||
var replayGroup = new ol.render.canvas.ReplayGroup(0, extent,
|
||||
tileResolution, layer.getRenderBuffer());
|
||||
tileResolution, source.getOverlaps(), layer.getRenderBuffer());
|
||||
var squaredTolerance = ol.renderer.vector.getSquaredTolerance(
|
||||
tileResolution, pixelRatio);
|
||||
|
||||
|
||||
@@ -259,7 +259,7 @@ ol.renderer.dom.VectorLayer.prototype.prepareFrame = function(frameState, layerS
|
||||
var replayGroup =
|
||||
new ol.render.canvas.ReplayGroup(
|
||||
ol.renderer.vector.getTolerance(resolution, pixelRatio), extent,
|
||||
resolution, vectorLayer.getRenderBuffer());
|
||||
resolution, vectorSource.getOverlaps(), vectorLayer.getRenderBuffer());
|
||||
vectorSource.loadFeatures(extent, resolution, projection);
|
||||
/**
|
||||
* @param {ol.Feature} feature Feature.
|
||||
|
||||
@@ -113,7 +113,7 @@ ol.source.ImageVector.prototype.canvasFunctionInternal_ = function(extent, resol
|
||||
|
||||
var replayGroup = new ol.render.canvas.ReplayGroup(
|
||||
ol.renderer.vector.getTolerance(resolution, pixelRatio), extent,
|
||||
resolution, this.renderBuffer_);
|
||||
resolution, this.source_.getOverlaps(), this.renderBuffer_);
|
||||
|
||||
this.source_.loadFeatures(extent, resolution, projection);
|
||||
|
||||
|
||||
@@ -94,6 +94,12 @@ ol.source.Vector = function(opt_options) {
|
||||
*/
|
||||
this.format_ = options.format;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.overlaps_ = options.overlaps == undefined ? true : options.overlaps;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {string|ol.FeatureUrlFunction|undefined}
|
||||
@@ -695,6 +701,14 @@ ol.source.Vector.prototype.getFormat = function() {
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {boolean} The source can have overlapping geometries.
|
||||
*/
|
||||
ol.source.Vector.prototype.getOverlaps = function() {
|
||||
return this.overlaps_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get the url associated with this source.
|
||||
*
|
||||
|
||||
@@ -52,6 +52,12 @@ ol.source.VectorTile = function(options) {
|
||||
*/
|
||||
this.format_ = options.format ? options.format : null;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.overlaps_ = options.overlaps || true;
|
||||
|
||||
/**
|
||||
* @protected
|
||||
* @type {function(new: ol.VectorTile, ol.TileCoord, ol.Tile.State, string,
|
||||
@@ -63,6 +69,14 @@ ol.source.VectorTile = function(options) {
|
||||
ol.inherits(ol.source.VectorTile, ol.source.UrlTile);
|
||||
|
||||
|
||||
/**
|
||||
* @return {boolean} The source can have overlapping geometries.
|
||||
*/
|
||||
ol.source.VectorTile.prototype.getOverlaps = function() {
|
||||
return this.overlaps_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
|
||||
33
test.html
Normal file
33
test.html
Normal file
@@ -0,0 +1,33 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<link rel="stylesheet" href="css/ol.css" type="text/css">
|
||||
<style>
|
||||
.map {
|
||||
height: 400px;
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
||||
<title>OpenLayers 3 example</title>
|
||||
<script src="build/ol.js" type="text/javascript"></script>
|
||||
</head>
|
||||
<body>
|
||||
<h2>My Map</h2>
|
||||
<div id="map" class="map"></div>
|
||||
<script type="text/javascript">
|
||||
var map = new ol.Map({
|
||||
target: 'map',
|
||||
layers: [
|
||||
new ol.layer.Tile({
|
||||
source: new ol.source.OSM()
|
||||
})
|
||||
],
|
||||
view: new ol.View({
|
||||
center: ol.proj.fromLonLat([37.41, 8.82]),
|
||||
zoom: 4
|
||||
})
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -103,20 +103,6 @@ describe('ol.color', function() {
|
||||
|
||||
});
|
||||
|
||||
describe('ol.color.isRgba', function() {
|
||||
it('identifies rgba arrays', function() {
|
||||
expect(ol.color.isRgba([255, 255, 255, 1])).to.be(true);
|
||||
expect(ol.color.isRgba([255, 255, 255])).to.be(false);
|
||||
});
|
||||
it('identifies rgba strings', function() {
|
||||
expect(ol.color.isRgba('rgba(255,255,255,1)')).to.be(true);
|
||||
expect(ol.color.isRgba('rgb(255,255,255)')).to.be(false);
|
||||
expect(ol.color.isRgba('#FFF')).to.be(false);
|
||||
expect(ol.color.isRgba('#FFFFFF')).to.be(false);
|
||||
expect(ol.color.isRgba('red')).to.be(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('ol.color.isValid', function() {
|
||||
|
||||
it('identifies valid colors', function() {
|
||||
|
||||
@@ -5,11 +5,11 @@ describe('ol.render.canvas.ReplayGroup', function() {
|
||||
describe('#replay', function() {
|
||||
|
||||
var context, replay, fillCount, strokeCount, beginPathCount;
|
||||
var feature1, feature2, feature3, style1, style2, style3, transform;
|
||||
var feature1, feature2, feature3, style1, style2, transform;
|
||||
|
||||
beforeEach(function() {
|
||||
transform = goog.vec.Mat4.createNumber();
|
||||
replay = new ol.render.canvas.ReplayGroup(1, [-180, -90, 180, 90], 1);
|
||||
replay = new ol.render.canvas.ReplayGroup(1, [-180, -90, 180, 90], 1, false);
|
||||
feature1 = new ol.Feature(new ol.geom.Polygon(
|
||||
[[[-90, -45], [-90, 0], [0, 0], [0, -45], [-90, -45]]]));
|
||||
feature2 = new ol.Feature(new ol.geom.Polygon(
|
||||
@@ -24,10 +24,6 @@ describe('ol.render.canvas.ReplayGroup', function() {
|
||||
fill: new ol.style.Fill({color: 'white'}),
|
||||
stroke: new ol.style.Stroke({color: 'black', width: 1})
|
||||
});
|
||||
style3 = new ol.style.Style({
|
||||
fill: new ol.style.Fill({color: 'rgba(255,255,255,0.8)'}),
|
||||
stroke: new ol.style.Stroke({color: 'rgba(0,0,0,0.8)', width: 1})
|
||||
});
|
||||
fillCount = 0;
|
||||
strokeCount = 0;
|
||||
beginPathCount = 0;
|
||||
@@ -121,10 +117,11 @@ describe('ol.render.canvas.ReplayGroup', function() {
|
||||
expect(beginPathCount).to.be(1);
|
||||
});
|
||||
|
||||
it('does not batch when transparent fills/strokes are used', function() {
|
||||
ol.renderer.vector.renderFeature(replay, feature1, style3, 1);
|
||||
ol.renderer.vector.renderFeature(replay, feature2, style3, 1);
|
||||
ol.renderer.vector.renderFeature(replay, feature3, style3, 1);
|
||||
it('does not batch when overlaps is set to true', function() {
|
||||
replay = new ol.render.canvas.ReplayGroup(1, [-180, -90, 180, 90], 1, true);
|
||||
ol.renderer.vector.renderFeature(replay, feature1, style1, 1);
|
||||
ol.renderer.vector.renderFeature(replay, feature2, style1, 1);
|
||||
ol.renderer.vector.renderFeature(replay, feature3, style1, 1);
|
||||
replay.replay(context, 1, transform, 0, {});
|
||||
expect(fillCount).to.be(3);
|
||||
expect(strokeCount).to.be(3);
|
||||
@@ -141,7 +138,7 @@ describe('ol.render.canvas.Replay', function() {
|
||||
it('creates a new replay batch', function() {
|
||||
var tolerance = 10;
|
||||
var extent = [-180, -90, 180, 90];
|
||||
var replay = new ol.render.canvas.Replay(tolerance, extent, 1);
|
||||
var replay = new ol.render.canvas.Replay(tolerance, extent, 1, true);
|
||||
expect(replay).to.be.a(ol.render.canvas.Replay);
|
||||
});
|
||||
|
||||
@@ -151,7 +148,7 @@ describe('ol.render.canvas.Replay', function() {
|
||||
|
||||
var replay;
|
||||
beforeEach(function() {
|
||||
replay = new ol.render.canvas.Replay(1, [-180, -90, 180, 90], 1);
|
||||
replay = new ol.render.canvas.Replay(1, [-180, -90, 180, 90], 1, true);
|
||||
});
|
||||
|
||||
it('appends coordinates that are within the max extent', function() {
|
||||
|
||||
@@ -87,6 +87,9 @@ describe('ol.rendering.layer.Vector', function() {
|
||||
|
||||
it('renders fill/stroke batches correctly with the canvas renderer', function(done) {
|
||||
map = createMap('canvas');
|
||||
source = new ol.source.Vector({
|
||||
overlaps: false
|
||||
});
|
||||
addPolygon(100);
|
||||
addCircle(200);
|
||||
addPolygon(250);
|
||||
|
||||
Reference in New Issue
Block a user