diff --git a/changelog/upgrade-notes.md b/changelog/upgrade-notes.md index 08853ed983..30c10d2b75 100644 --- a/changelog/upgrade-notes.md +++ b/changelog/upgrade-notes.md @@ -2,6 +2,10 @@ ### Next Release +#### Behavior change for polygon labels + +Polygon labels are now only rendered when the label does not exceed the polygon at the label position. To get the old behavior, configure your `ol.style.Text` with `exceedLength: true`. + #### Minor change for custom `tileLoadFunction` with `ol.source.VectorTile` It is no longer necessary to set the projection on the tile. Instead, the `readFeatures` method must be called with the tile's extent as `extent` option and the view's projection as `featureProjection`. diff --git a/externs/olx.js b/externs/olx.js index 7cc408b62d..8b3cc7a22c 100644 --- a/externs/olx.js +++ b/externs/olx.js @@ -7676,8 +7676,9 @@ olx.style.TextOptions; /** - * When `placement` is set to `'line'`, allow text to exceed the length of the - * path that it follows. Default is `false`. + * For polygon labels or when `placement` is set to `'line'`, allow text to + * exceed the width of the polygon at the the label position or the length of + * the path that it follows. Default is `false`. * @type {boolean|undefined} * @api */ diff --git a/src/ol/render/canvas/textreplay.js b/src/ol/render/canvas/textreplay.js index a8a13274b9..d39abc05bf 100644 --- a/src/ol/render/canvas/textreplay.js +++ b/src/ol/render/canvas/textreplay.js @@ -197,13 +197,13 @@ ol.render.canvas.TextReplay.prototype.drawText = function(geometry, feature) { return; } - this.beginGeometry(geometry, feature); var begin = this.coordinates.length; var geometryType = geometry.getType(); var flatCoordinates = null; var end = 2; var stride = 2; + var i, ii; if (this.textState_.placement === ol.style.TextPlacement.LINE) { var ends; @@ -218,10 +218,11 @@ ol.render.canvas.TextReplay.prototype.drawText = function(geometry, feature) { } else if (geometryType == ol.geom.GeometryType.MULTI_POLYGON) { var endss = geometry.getEndss(); ends = []; - for (var i = 0, ii = endss.length; i < ii; ++i) { + for (i = 0, ii = endss.length; i < ii; ++i) { ends.push(endss[i][0]); } } + this.beginGeometry(geometry, feature); var textAlign = textState.textAlign; var flatOffset = 0; var flatEnd; @@ -239,8 +240,11 @@ ol.render.canvas.TextReplay.prototype.drawText = function(geometry, feature) { this.drawChars_(begin, end); begin = end; } + this.endGeometry(geometry, feature); } else { + var label = this.getImage_(this.text_, !!this.textFillState_, !!this.textStrokeState_); + var width = label.width / this.pixelRatio; switch (geometryType) { case ol.geom.GeometryType.POINT: case ol.geom.GeometryType.MULTI_POINT: @@ -259,18 +263,31 @@ ol.render.canvas.TextReplay.prototype.drawText = function(geometry, feature) { break; case ol.geom.GeometryType.POLYGON: flatCoordinates = /** @type {ol.geom.Polygon} */ (geometry).getFlatInteriorPoint(); + if (!textState.exceedLength && flatCoordinates[2] / this.resolution < width) { + return; + } + stride = 3; break; case ol.geom.GeometryType.MULTI_POLYGON: - flatCoordinates = /** @type {ol.geom.MultiPolygon} */ (geometry).getFlatInteriorPoints(); + var interiorPoints = /** @type {ol.geom.MultiPolygon} */ (geometry).getFlatInteriorPoints(); + flatCoordinates = []; + for (i = 0, ii = interiorPoints.length; i < ii; i += 3) { + if (textState.exceedLength || interiorPoints[i + 2] / this.resolution >= width) { + flatCoordinates.push(interiorPoints[i], interiorPoints[i + 1]); + } + } end = flatCoordinates.length; + if (end == 0) { + return; + } break; default: } end = this.appendFlatCoordinates(flatCoordinates, 0, end, stride, false, false); - this.drawTextImage_(begin, end); + this.beginGeometry(geometry, feature); + this.drawTextImage_(label, begin, end); + this.endGeometry(geometry, feature); } - - this.endGeometry(geometry, feature); }; @@ -343,10 +360,11 @@ ol.render.canvas.TextReplay.prototype.getImage_ = function(text, fill, stroke) { /** * @private + * @param {HTMLCanvasElement} label Label. * @param {number} begin Begin. * @param {number} end End. */ -ol.render.canvas.TextReplay.prototype.drawTextImage_ = function(begin, end) { +ol.render.canvas.TextReplay.prototype.drawTextImage_ = function(label, begin, end) { var textState = this.textState_; var strokeState = this.textStrokeState_; var pixelRatio = this.pixelRatio; @@ -354,8 +372,6 @@ ol.render.canvas.TextReplay.prototype.drawTextImage_ = function(begin, end) { var baseline = ol.render.replay.TEXT_ALIGN[textState.textBaseline]; var strokeWidth = strokeState && strokeState.lineWidth ? strokeState.lineWidth : 0; - var label = this.getImage_(this.text_, !!this.textFillState_, !!this.textStrokeState_); - var anchorX = align * label.width / pixelRatio + 2 * (0.5 - align) * strokeWidth; var anchorY = baseline * label.height / pixelRatio + 2 * (0.5 - baseline) * strokeWidth; this.instructions.push([ol.render.canvas.Instruction.DRAW_IMAGE, begin, end, diff --git a/test/spec/ol/render/canvas/textreplay.test.js b/test/spec/ol/render/canvas/textreplay.test.js new file mode 100644 index 0000000000..730871f95f --- /dev/null +++ b/test/spec/ol/render/canvas/textreplay.test.js @@ -0,0 +1,48 @@ +goog.require('ol.Feature'); +goog.require('ol.geom.MultiPolygon'); +goog.require('ol.geom.Polygon'); +goog.require('ol.render.canvas.TextReplay'); +goog.require('ol.style.Text'); + +describe('ol.render.canvas.TextReplay', function() { + + it('renders polygon labels only when they fit', function() { + var replay = new ol.render.canvas.TextReplay(1, [-180, -90, 180, 90], 0.02, 1, true); + var geometry = new ol.geom.Polygon([[[0, 0], [0, 1], [1, 1], [1, 0], [0, 0]]]); + var feature = new ol.Feature(geometry); + + replay.setTextStyle(new ol.style.Text({ + text: 'This is a long text' + })); + replay.drawText(geometry, feature); + expect(replay.instructions.length).to.be(0); + + replay.setTextStyle(new ol.style.Text({ + text: 'short' + })); + replay.drawText(geometry, feature); + expect(replay.instructions.length).to.be(3); + }); + + it('renders multipolygon labels only when they fit', function() { + var replay = new ol.render.canvas.TextReplay(1, [-180, -90, 180, 90], 0.02, 1, true); + var geometry = new ol.geom.MultiPolygon([ + [[[0, 0], [0, 1], [1, 1], [1, 0], [0, 0]]], + [[[1, 1], [1, 2], [2, 2], [2, 1], [1, 1]]] + ]); + var feature = new ol.Feature(geometry); + + replay.setTextStyle(new ol.style.Text({ + text: 'This is a long text' + })); + replay.drawText(geometry, feature); + expect(replay.instructions.length).to.be(0); + + replay.setTextStyle(new ol.style.Text({ + text: 'short' + })); + replay.drawText(geometry, feature); + expect(replay.instructions.length).to.be(3); + }); + +});