diff --git a/rendering/cases/layer-vectortile-rotate-text/expected.png b/rendering/cases/layer-vectortile-rotate-text/expected.png new file mode 100644 index 0000000000..c035e9ec7e Binary files /dev/null and b/rendering/cases/layer-vectortile-rotate-text/expected.png differ diff --git a/rendering/cases/layer-vectortile-rotate-text/main.js b/rendering/cases/layer-vectortile-rotate-text/main.js new file mode 100644 index 0000000000..0056e4748a --- /dev/null +++ b/rendering/cases/layer-vectortile-rotate-text/main.js @@ -0,0 +1,44 @@ +import MVT from '../../../src/ol/format/MVT.js'; +import Map from '../../../src/ol/Map.js'; +import VectorTileLayer from '../../../src/ol/layer/VectorTile.js'; +import VectorTileSource from '../../../src/ol/source/VectorTile.js'; +import View from '../../../src/ol/View.js'; +import {Stroke, Style, Text} from '../../../src/ol/style.js'; +import {createXYZ} from '../../../src/ol/tilegrid.js'; + +new Map({ + layers: [ + new VectorTileLayer({ + style: function (feature, resolution) { + const name = feature.get('name'); + if (feature.getGeometry().getType() === 'LineString' && name) { + return new Style({ + stroke: new Stroke({ + width: 2, + color: 'red', + }), + text: new Text({ + text: name, + font: 'italic bold 18px Ubuntu', + placement: 'line', + }), + }); + } + }, + source: new VectorTileSource({ + format: new MVT(), + tileGrid: createXYZ(), + url: '/data/tiles/mapbox-streets-v6/{z}/{x}/{y}.vector.pbf', + transition: 0, + }), + }), + ], + target: 'map', + view: new View({ + center: [1825927.7316762917, 6143091.089223046], + rotation: Math.PI / 2, + zoom: 14, + }), +}); + +render({message: 'Vector tile layer has upright labels', tolerance: 0.01}); diff --git a/src/ol/geom/flat/textpath.js b/src/ol/geom/flat/textpath.js index e0f4f2c49b..89b4a04add 100644 --- a/src/ol/geom/flat/textpath.js +++ b/src/ol/geom/flat/textpath.js @@ -2,6 +2,7 @@ * @module ol/geom/flat/textpath */ import {lerp} from '../../math.js'; +import {rotate} from './transform.js'; /** * @param {Array} flatCoordinates Path to put text on. @@ -15,6 +16,7 @@ import {lerp} from '../../math.js'; * @param {function(string, string, Object):number} measureAndCacheTextWidth Measure and cache text width. * @param {string} font The font. * @param {Object} cache A cache of measured widths. + * @param {number} rotation Rotation to apply to the flatCoordinates to determine whether text needs to be reversed. * @return {Array>} The result array (or null if `maxAngle` was * exceeded). Entries of the array are x, y, anchorX, angle, chunk. */ @@ -29,12 +31,28 @@ export function drawTextOnPath( scale, measureAndCacheTextWidth, font, - cache + cache, + rotation ) { const result = []; // Keep text upright - const reverse = flatCoordinates[offset] > flatCoordinates[end - stride]; + let reverse; + if (rotation) { + const rotatedCoordinates = rotate( + flatCoordinates, + offset, + end, + stride, + rotation, + [flatCoordinates[offset], flatCoordinates[offset + 1]] + ); + reverse = + rotatedCoordinates[0] > + rotatedCoordinates[rotatedCoordinates.length - stride]; + } else { + reverse = flatCoordinates[offset] > flatCoordinates[end - stride]; + } const numChars = text.length; diff --git a/src/ol/render/canvas/Executor.js b/src/ol/render/canvas/Executor.js index 1df7430306..5fdd1e6c54 100644 --- a/src/ol/render/canvas/Executor.js +++ b/src/ol/render/canvas/Executor.js @@ -957,7 +957,8 @@ class Executor { Math.abs(textScale[0]), measureAndCacheTextWidth, font, - cachedWidths + cachedWidths, + viewRotationFromTransform ? 0 : this.viewRotation_ ); if (parts) { let rendered = false;