From 8e95d94f3e39c7c9279d0c2e39f72eb5b19d1fa8 Mon Sep 17 00:00:00 2001 From: Frederic Junod Date: Wed, 16 Mar 2016 13:47:18 +0100 Subject: [PATCH] Add rotateWithView option to ol.style.Text --- externs/olx.js | 9 ++ src/ol/render/canvas/immediate.js | 18 ++- src/ol/render/canvas/replay.js | 14 ++- src/ol/style/text.js | 16 +++ .../spec/ol/style/expected/text-canvas.png | Bin 0 -> 2922 bytes .../ol/style/expected/text-rotated-canvas.png | Bin 0 -> 3108 bytes test_rendering/spec/ol/style/text.test.js | 106 ++++++++++++++++++ 7 files changed, 159 insertions(+), 4 deletions(-) create mode 100644 test_rendering/spec/ol/style/expected/text-canvas.png create mode 100644 test_rendering/spec/ol/style/expected/text-rotated-canvas.png create mode 100644 test_rendering/spec/ol/style/text.test.js diff --git a/externs/olx.js b/externs/olx.js index b009fdaaee..190ba3fb45 100644 --- a/externs/olx.js +++ b/externs/olx.js @@ -6840,6 +6840,14 @@ olx.style.RegularShapeOptions.prototype.snapToPixel; olx.style.RegularShapeOptions.prototype.stroke; +/** + * Whether to rotate the text with the view. Default is `false`. + * @type {boolean|undefined} + * @api + */ +olx.style.TextOptions.prototype.rotateWithView; + + /** * Rotation in radians (positive rotation clockwise). Default is `0`. * @type {number|undefined} @@ -6937,6 +6945,7 @@ olx.style.StrokeOptions.prototype.width; * offsetX: (number|undefined), * offsetY: (number|undefined), * scale: (number|undefined), + * rotateWithView: (boolean|undefined), * rotation: (number|undefined), * text: (string|undefined), * textAlign: (string|undefined), diff --git a/src/ol/render/canvas/immediate.js b/src/ol/render/canvas/immediate.js index bd254e271c..ddcc17418a 100644 --- a/src/ol/render/canvas/immediate.js +++ b/src/ol/render/canvas/immediate.js @@ -189,6 +189,12 @@ ol.render.canvas.Immediate = function(context, pixelRatio, extent, transform, vi */ this.textOffsetY_ = 0; + /** + * @private + * @type {boolean} + */ + this.textRotateWithView_ = false; + /** * @private * @type {number} @@ -318,14 +324,18 @@ ol.render.canvas.Immediate.prototype.drawText_ = function(flatCoordinates, offse flatCoordinates, offset, end, stride, this.transform_, this.pixelCoordinates_); var context = this.context_; + var rotation = this.textRotation_; + if (this.textRotateWithView_) { + rotation += this.viewRotation_; + } for (; offset < end; offset += stride) { var x = pixelCoordinates[offset] + this.textOffsetX_; var y = pixelCoordinates[offset + 1] + this.textOffsetY_; - if (this.textRotation_ !== 0 || this.textScale_ != 1) { + if (rotation !== 0 || this.textScale_ != 1) { var localTransform = ol.transform.compose(this.tmpLocalTransform_, x, y, this.textScale_, this.textScale_, - this.textRotation_, + rotation, -x, -y); context.setTransform.apply(context, localTransform); } @@ -336,7 +346,7 @@ ol.render.canvas.Immediate.prototype.drawText_ = function(flatCoordinates, offse context.fillText(this.text_, x, y); } } - if (this.textRotation_ !== 0 || this.textScale_ != 1) { + if (rotation !== 0 || this.textScale_ != 1) { context.setTransform(1, 0, 0, 1, 0, 0); } }; @@ -918,6 +928,7 @@ ol.render.canvas.Immediate.prototype.setTextStyle = function(textStyle) { var textFont = textStyle.getFont(); var textOffsetX = textStyle.getOffsetX(); var textOffsetY = textStyle.getOffsetY(); + var textRotateWithView = textStyle.getRotateWithView(); var textRotation = textStyle.getRotation(); var textScale = textStyle.getScale(); var textText = textStyle.getText(); @@ -936,6 +947,7 @@ ol.render.canvas.Immediate.prototype.setTextStyle = function(textStyle) { textOffsetX !== undefined ? (this.pixelRatio_ * textOffsetX) : 0; this.textOffsetY_ = textOffsetY !== undefined ? (this.pixelRatio_ * textOffsetY) : 0; + this.textRotateWithView_ = textRotateWithView !== undefined ? textRotateWithView : false; this.textRotation_ = textRotation !== undefined ? textRotation : 0; this.textScale_ = this.pixelRatio_ * (textScale !== undefined ? textScale : 1); diff --git a/src/ol/render/canvas/replay.js b/src/ol/render/canvas/replay.js index 1de3481ca2..9b3e14440a 100644 --- a/src/ol/render/canvas/replay.js +++ b/src/ol/render/canvas/replay.js @@ -384,6 +384,10 @@ ol.render.canvas.Replay.prototype.replay_ = function( goog.DEBUG && console.assert(typeof instruction[9] === 'boolean', '10th instruction should be a boolean'); stroke = /** @type {boolean} */ (instruction[9]); + rotateWithView = /** @type {boolean} */ (instruction[10]); + if (rotateWithView) { + rotation += viewRotation; + } for (; d < dd; d += 2) { x = pixelCoordinates[d] + offsetX; y = pixelCoordinates[d + 1] + offsetY; @@ -1545,6 +1549,12 @@ ol.render.canvas.TextReplay = function(tolerance, maxExtent, resolution) { */ this.textOffsetY_ = 0; + /** + * @private + * @type {boolean|undefined} + */ + this.textRotateWithView_ = undefined; + /** * @private * @type {number} @@ -1603,7 +1613,7 @@ ol.render.canvas.TextReplay.prototype.drawText = function(flatCoordinates, offse var drawTextInstruction = [ ol.render.canvas.Instruction.DRAW_TEXT, myBegin, myEnd, this.text_, this.textOffsetX_, this.textOffsetY_, this.textRotation_, this.textScale_, - fill, stroke]; + fill, stroke, this.textRotateWithView_]; this.instructions.push(drawTextInstruction); this.hitDetectionInstructions.push(drawTextInstruction); this.endGeometry(geometry, feature); @@ -1773,6 +1783,7 @@ ol.render.canvas.TextReplay.prototype.setTextStyle = function(textStyle) { var textFont = textStyle.getFont(); var textOffsetX = textStyle.getOffsetX(); var textOffsetY = textStyle.getOffsetY(); + var textRotateWithView = textStyle.getRotateWithView(); var textRotation = textStyle.getRotation(); var textScale = textStyle.getScale(); var textText = textStyle.getText(); @@ -1799,6 +1810,7 @@ ol.render.canvas.TextReplay.prototype.setTextStyle = function(textStyle) { this.text_ = textText !== undefined ? textText : ''; this.textOffsetX_ = textOffsetX !== undefined ? textOffsetX : 0; this.textOffsetY_ = textOffsetY !== undefined ? textOffsetY : 0; + this.textRotateWithView_ = textRotateWithView !== undefined ? textRotateWithView : false; this.textRotation_ = textRotation !== undefined ? textRotation : 0; this.textScale_ = textScale !== undefined ? textScale : 1; } diff --git a/src/ol/style/text.js b/src/ol/style/text.js index 4f62e83b69..8a8e31106c 100644 --- a/src/ol/style/text.js +++ b/src/ol/style/text.js @@ -28,6 +28,12 @@ ol.style.Text = function(opt_options) { */ this.rotation_ = options.rotation; + /** + * @private + * @type {boolean|undefined} + */ + this.rotateWithView_ = options.rotateWithView; + /** * @private * @type {number|undefined} @@ -129,6 +135,16 @@ ol.style.Text.prototype.getFill = function() { }; +/** + * Determine whether the text rotates with the map. + * @return {boolean|undefined} Rotate with map. + * @api + */ +ol.style.Text.prototype.getRotateWithView = function() { + return this.rotateWithView_; +}; + + /** * Get the text rotation. * @return {number|undefined} Rotation. diff --git a/test_rendering/spec/ol/style/expected/text-canvas.png b/test_rendering/spec/ol/style/expected/text-canvas.png new file mode 100644 index 0000000000000000000000000000000000000000..b2e9b26d452e8ddce639f17adf379364b8a896e5 GIT binary patch literal 2922 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 literal 0 HcmV?d00001 diff --git a/test_rendering/spec/ol/style/text.test.js b/test_rendering/spec/ol/style/text.test.js new file mode 100644 index 0000000000..ec162b955c --- /dev/null +++ b/test_rendering/spec/ol/style/text.test.js @@ -0,0 +1,106 @@ +goog.provide('ol.test.rendering.style.Text'); + +goog.require('ol.Feature'); +goog.require('ol.geom.Point'); +goog.require('ol.Map'); +goog.require('ol.View'); +goog.require('ol.layer.Vector'); +goog.require('ol.source.Vector'); +goog.require('ol.style.Text'); +goog.require('ol.style.Fill'); +goog.require('ol.style.Style'); +goog.require('ol.style.Stroke'); + +describe('ol.rendering.style.Text', function() { + + var target, map, vectorSource; + + function createMap(renderer) { + target = createMapDiv(200, 200); + + vectorSource = new ol.source.Vector(); + var vectorLayer = new ol.layer.Vector({ + source: vectorSource + }); + + map = new ol.Map({ + target: target, + renderer: renderer, + layers: [vectorLayer], + view: new ol.View({ + projection: 'EPSG:4326', + center: [0, 0], + resolution: 1 + }) + }); + return map; + } + + describe('#render', function() { + afterEach(function() { + disposeMap(map); + }); + + function createFeatures() { + var feature; + feature = new ol.Feature({ + geometry: new ol.geom.Point([-20, 18]) + }); + feature.setStyle(new ol.style.Style({ + text: new ol.style.Text({ + text: 'hello', + font: '10px' + }) + })); + vectorSource.addFeature(feature); + + feature = new ol.Feature({ + geometry: new ol.geom.Point([-10, 0]) + }); + feature.setStyle(new ol.style.Style({ + text: new ol.style.Text({ + text: 'hello', + fill: new ol.style.Fill({ + color: 'red', + font: '12px' + }), + stroke: new ol.style.Stroke({ + color: '#000', + width: 3 + }) + }) + })); + vectorSource.addFeature(feature); + + feature = new ol.Feature({ + geometry: new ol.geom.Point([20, 10]) + }); + feature.setStyle(new ol.style.Style({ + text: new ol.style.Text({ + rotateWithView: true, + text: 'hello', + font: '10px', + stroke: new ol.style.Stroke({ + color: [10, 10, 10, 0.5] + }) + }) + })); + vectorSource.addFeature(feature); + + } + + it('tests the canvas renderer without rotation', function(done) { + map = createMap('canvas'); + createFeatures(); + expectResemble(map, 'spec/ol/style/expected/text-canvas.png', IMAGE_TOLERANCE, done); + }); + + it('tests the canvas renderer with rotation', function(done) { + map = createMap('canvas'); + createFeatures(); + map.getView().setRotation(Math.PI / 7); + expectResemble(map, 'spec/ol/style/expected/text-rotated-canvas.png', IMAGE_TOLERANCE, done); + }); + + }); +});