Skip to content

Commit

Permalink
Add keepUpright parameter
Browse files Browse the repository at this point in the history
This parameter allows to control whether text can be rendered upside-down
when rendering along a line or polygon. This can be useful when the text
has to follow the line direction regardless of its orientation, like an
arrow pointing the direction of the line element.

This setting already exists in Mapbox Style Spec, so ol-mapbox-style will
be able to follow more closely some style definitions.
  • Loading branch information
leyan committed Oct 17, 2024
1 parent 9e574da commit 07b4906
Show file tree
Hide file tree
Showing 4 changed files with 52 additions and 8 deletions.
20 changes: 12 additions & 8 deletions src/ol/geom/flat/textpath.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {rotate} from './transform.js';
* @param {string} font The font.
* @param {Object<string, number>} cache A cache of measured widths.
* @param {number} rotation Rotation to apply to the flatCoordinates to determine whether text needs to be reversed.
* @param {boolean} keepUpright Whether the text needs to be kept upright
* @return {Array<Array<*>>|null} The result array (or null if `maxAngle` was
* exceeded). Entries of the array are x, y, anchorX, angle, chunk.
*/
Expand All @@ -33,6 +34,7 @@ export function drawTextOnPath(
font,
cache,
rotation,
keepUpright = true,
) {
let x2 = flatCoordinates[offset];
let y2 = flatCoordinates[offset + 1];
Expand Down Expand Up @@ -69,14 +71,16 @@ export function drawTextOnPath(
const endX = lerp(x1, x2, interpolate);
const endY = lerp(y1, y2, interpolate);

// Keep text upright
let reverse;
if (rotation) {
const flat = [beginX, beginY, endX, endY];
rotate(flat, 0, 4, 2, rotation, flat, flat);
reverse = flat[0] > flat[2];
} else {
reverse = beginX > endX;
// Keep text upright if the option is selected
let reverse = false;
if (keepUpright) {
if (rotation) {
const flat = [beginX, beginY, endX, endY];
rotate(flat, 0, 4, 2, rotation, flat, flat);
reverse = flat[0] > flat[2];
} else {
reverse = beginX > endX;
}
}

const PI = Math.PI;
Expand Down
2 changes: 2 additions & 0 deletions src/ol/render/canvas/Executor.js
Original file line number Diff line number Diff line change
Expand Up @@ -1001,6 +1001,7 @@ class Executor {
];
declutterMode = instruction[14] || 'declutter';

const textKeepUpright = /** @type {boolean} */ (instruction[15]);
const textState = this.textStates[textKey];
const font = textState.font;
const textScale = [
Expand Down Expand Up @@ -1037,6 +1038,7 @@ class Executor {
font,
cachedWidths,
viewRotationFromTransform ? 0 : this.viewRotation_,
textKeepUpright,
);
drawChars: if (parts) {
/** @type {Array<ReplayImageOrLabelArgs>} */
Expand Down
11 changes: 11 additions & 0 deletions src/ol/render/canvas/TextBuilder.js
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,12 @@ class CanvasTextBuilder extends CanvasBuilder {
*/
this.textRotateWithView_ = undefined;

/**
* @private
* @type {boolean|undefined}
*/
this.textKeepUpright_ = undefined;

/**
* @private
* @type {number}
Expand Down Expand Up @@ -538,6 +544,7 @@ class CanvasTextBuilder extends CanvasBuilder {
textKey,
1,
this.declutterMode_,
this.textKeepUpright_,
]);
this.hitDetectionInstructions.push([
CanvasInstruction.DRAW_CHARS,
Expand All @@ -555,6 +562,7 @@ class CanvasTextBuilder extends CanvasBuilder {
textKey,
1 / pixelRatio,
this.declutterMode_,
this.textKeepUpright_,
]);
}

Expand Down Expand Up @@ -632,12 +640,15 @@ class CanvasTextBuilder extends CanvasBuilder {
const textOffsetX = textStyle.getOffsetX();
const textOffsetY = textStyle.getOffsetY();
const textRotateWithView = textStyle.getRotateWithView();
const textKeepUpright = textStyle.getKeepUpright();
const textRotation = textStyle.getRotation();
this.text_ = textStyle.getText() || '';
this.textOffsetX_ = textOffsetX === undefined ? 0 : textOffsetX;
this.textOffsetY_ = textOffsetY === undefined ? 0 : textOffsetY;
this.textRotateWithView_ =
textRotateWithView === undefined ? false : textRotateWithView;
this.textKeepUpright_ =
textKeepUpright === undefined ? true : textKeepUpright;
this.textRotation_ = textRotation === undefined ? 0 : textRotation;

this.strokeKey_ = strokeState
Expand Down
27 changes: 27 additions & 0 deletions src/ol/style/Text.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ const DEFAULT_FILL_COLOR = '#333';
* the distance between two text anchors in pixels. Only available when `placement` is set to `'line'`. Overrides 'textAlign'.
* @property {number|import("../size.js").Size} [scale] Scale.
* @property {boolean} [rotateWithView=false] Whether to rotate the text with the view.
* @property {boolean} [keepUpright=true] Whether the text can be rotated 180° to prevent being rendered upside down.
* @property {number} [rotation=0] Rotation in radians (positive rotation clockwise).
* @property {string|Array<string>} [text] Text content or rich text content. For plain text provide a string, which can
* contain line breaks (`\n`). For rich text provide an array of text/font tuples. A tuple consists of the text to
Expand Down Expand Up @@ -95,6 +96,12 @@ class Text {
*/
this.rotateWithView_ = options.rotateWithView;

/**
* @private
* @type {boolean|undefined}
*/
this.keepUpright_ = options.keepUpright;

/**
* @private
* @type {number|import("../size.js").Size|undefined}
Expand Down Expand Up @@ -228,6 +235,7 @@ class Text {
overflow: this.getOverflow(),
rotation: this.getRotation(),
rotateWithView: this.getRotateWithView(),
keepUpright: this.getKeepUpright(),
scale: Array.isArray(scale) ? scale.slice() : scale,
text: this.getText(),
textAlign: this.getTextAlign(),
Expand Down Expand Up @@ -329,6 +337,15 @@ class Text {
return this.rotateWithView_;
}

/**
* Determine whether the text can be rendered upside down.
* @return {boolean|undefined} Keep text upright.
* @api
*/
getKeepUpright() {
return this.keepUpright_;
}

/**
* Get the text rotation.
* @return {number|undefined} Rotation.
Expand Down Expand Up @@ -515,6 +532,16 @@ class Text {
this.rotateWithView_ = rotateWithView;
}

/**
* Set whether the text can be rendered upside down.
*
* @param {boolean} keepUpright Keep text upright.
* @api
*/
setKeepUpright(keepUpright) {
this.keepUpright_ = keepUpright;
}

/**
* Set the fill.
*
Expand Down

0 comments on commit 07b4906

Please sign in to comment.