From 5a61bb51f509ead937f95fb18fc4ad9198893ccd Mon Sep 17 00:00:00 2001 From: Denis <51781722+rycgar@users.noreply.github.com> Date: Mon, 11 Apr 2022 14:45:35 +0200 Subject: [PATCH 1/9] Extend Text.js: add justification option --- src/ol/style/Text.js | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/src/ol/style/Text.js b/src/ol/style/Text.js index ae936e6949..850eaa90f3 100644 --- a/src/ol/style/Text.js +++ b/src/ol/style/Text.js @@ -35,6 +35,10 @@ const DEFAULT_FILL_COLOR = '#333'; * @property {string} [textAlign] Text alignment. Possible values: 'left', 'right', 'center', 'end' or 'start'. * Default is 'center' for `placement: 'point'`. For `placement: 'line'`, the default is to let the renderer choose a * placement where `maxAngle` is not exceeded. + * @property {string} [justify] Text justification within the text box. + * If not set, text is justified towards the `textAlign` anchor. + * Otherwise, use options `'left'`, `'center'`, or `'right'` to justify the text within the text box. + * See: https://github.com/openlayers/openlayers/issues/13481 * @property {string} [textBaseline='middle'] Text base line. Possible values: 'bottom', 'top', 'middle', 'alphabetic', * 'hanging', 'ideographic'. * @property {import("./Fill.js").default} [fill] Fill style. If none is provided, we'll use a dark fill-style (#333). @@ -101,6 +105,12 @@ class Text { */ this.textAlign_ = options.textAlign; + /** + * @private + * @type {string|undefined} + */ + this.justify_ = options.justify; + /** * @private * @type {string|undefined} @@ -194,6 +204,7 @@ class Text { scale: Array.isArray(scale) ? scale.slice() : scale, text: this.getText(), textAlign: this.getTextAlign(), + justify: this.getJustify(), textBaseline: this.getTextBaseline(), fill: this.getFill() ? this.getFill().clone() : undefined, stroke: this.getStroke() ? this.getStroke().clone() : undefined, @@ -334,6 +345,15 @@ class Text { return this.textAlign_; } + /** + * Get the justification. + * @return {string|undefined} Justification. + * @api + */ + getJustify() { + return this.justify_; + } + /** * Get the text baseline. * @return {string|undefined} Text baseline. @@ -501,6 +521,16 @@ class Text { this.textAlign_ = textAlign; } + /** + * Set the justification. + * + * @param {string|undefined} justify Justification. + * @api + */ + setJustify(justify) { + this.justify_ = justify; + } + /** * Set the text baseline. * From c45a443cf5513f3dcd201efcbd221b3ded7bf205 Mon Sep 17 00:00:00 2001 From: Denis <51781722+rycgar@users.noreply.github.com> Date: Mon, 11 Apr 2022 16:36:16 +0200 Subject: [PATCH 2/9] Add example for justify text --- examples/vector-labels-justify-text.html | 14 +++ examples/vector-labels-justify-text.js | 121 +++++++++++++++++++++++ 2 files changed, 135 insertions(+) create mode 100644 examples/vector-labels-justify-text.html create mode 100644 examples/vector-labels-justify-text.js diff --git a/examples/vector-labels-justify-text.html b/examples/vector-labels-justify-text.html new file mode 100644 index 0000000000..0047326081 --- /dev/null +++ b/examples/vector-labels-justify-text.html @@ -0,0 +1,14 @@ +--- +layout: example.html +title: Vector Labels - Justify Text +shortdesc: Example of text justification within a label. +docs: > + This example showcases how the text can be justified within the label box. + By default, the text is justified according to the `textAlign` option. + However, this option justifies the label itself according to the setting. + If one wants to change this behavior, it is possible to use the `justify` text style option. + For more information, see the discussion: + https://github.com/openlayers/openlayers/issues/13481 +tags: "vector, openstreetmap, label, rich-text" +--- +
diff --git a/examples/vector-labels-justify-text.js b/examples/vector-labels-justify-text.js new file mode 100644 index 0000000000..c752859d0a --- /dev/null +++ b/examples/vector-labels-justify-text.js @@ -0,0 +1,121 @@ +import Collection from '../src/ol/Collection.js'; +import Feature from '../src/ol/Feature.js'; +import GeoJSON from '../src/ol/format/GeoJSON.js'; +import Map from '../src/ol/Map.js'; +import Point from '../src/ol/geom/Point.js'; +import View from '../src/ol/View.js'; +import { + Circle as CircleStyle, + Fill, + Stroke, + Style, + Text, +} from '../src/ol/style.js'; +import {OSM, Vector as VectorSource} from '../src/ol/source.js'; +import {Tile as TileLayer, Vector as VectorLayer} from '../src/ol/layer.js'; + +const features = [ + { + geometry: new Point([-8300000, 6095000]), + textAlign: 'left', + }, + { + geometry: new Point([-8150000, 6095000]), + textAlign: 'center', + }, + { + geometry: new Point([-8000000, 6095000]), + textAlign: 'right', + }, + { + geometry: new Point([-8300000, 6025000]), + textAlign: 'left', + justify: 'center', + }, + { + geometry: new Point([-8150000, 6025000]), + textAlign: 'center', + justify: 'center', + }, + { + geometry: new Point([-8000000, 6025000]), + textAlign: 'right', + justify: 'center', + }, + { + geometry: new Point([-8300000, 5955000]), + textAlign: 'left', + justify: 'left', + }, + { + geometry: new Point([-8150000, 5955000]), + textAlign: 'center', + justify: 'left', + }, + { + geometry: new Point([-8000000, 5955000]), + textAlign: 'right', + justify: 'left', + }, +]; + +function createStyleFunction({textAlign, justify}) { + return new Style({ + image: new CircleStyle({ + radius: 10, + fill: new Fill({color: 'rgba(255, 0, 0, 0.1)'}), + stroke: new Stroke({color: 'red', width: 1}), + }), + text: new Text({ + textAlign, + justify, + text: [ + 'long text to emphasize justify', + '', + '\n', + '', + `textAlign: ${textAlign}`, + '', + '\n', + '', + `justify: ${justify}`, + '', + ], + fill: new Fill({ + color: [255, 255, 255, 1], + }), + backgroundFill: new Fill({ + color: [168, 50, 153, 0.8], + }), + }), + }); +} + +const vectorPoints = new VectorLayer({ + source: new VectorSource({ + features: new Collection( + features.map((featureOptions) => { + const feature = new Feature({ + geometry: featureOptions.geometry, + }); + feature.setStyle(createStyleFunction(featureOptions)); + return feature; + }) + ), + format: new GeoJSON(), + }), +}); + +const map = new Map({ + layers: [ + new TileLayer({ + source: new OSM(), + }), + vectorPoints, + ], + target: 'map', + view: new View({ + center: [-8150000, 6025000], + zoom: 8, + }), +}); From 4db25c86c8c5c1fc75f3e4028ee80acef7faba69 Mon Sep 17 00:00:00 2001 From: Denis <51781722+rycgar@users.noreply.github.com> Date: Tue, 12 Apr 2022 19:02:12 +0200 Subject: [PATCH 3/9] Implement text justify within the label box See: https://github.com/openlayers/openlayers/issues/13481 --- src/ol/render/canvas.js | 1 + src/ol/render/canvas/Executor.js | 11 +++++++---- src/ol/render/canvas/Immediate.js | 1 + src/ol/render/canvas/TextBuilder.js | 4 ++++ 4 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/ol/render/canvas.js b/src/ol/render/canvas.js index 6ec5947a58..46af528f7c 100644 --- a/src/ol/render/canvas.js +++ b/src/ol/render/canvas.js @@ -56,6 +56,7 @@ import {getFontParameters} from '../css.js'; * @typedef {Object} TextState * @property {string} font Font. * @property {string} [textAlign] TextAlign. + * @property {string} [justify] Justify. * @property {string} textBaseline TextBaseline. * @property {string} [placement] Placement. * @property {number} [maxAngle] MaxAngle. diff --git a/src/ol/render/canvas/Executor.js b/src/ol/render/canvas/Executor.js index 1a888b0d15..a5793d55b2 100644 --- a/src/ol/render/canvas/Executor.js +++ b/src/ol/render/canvas/Executor.js @@ -239,10 +239,13 @@ class Executor { textState.scale[1] * pixelRatio, ]; const textIsArray = Array.isArray(text); - const align = horizontalTextAlign( - textIsArray ? text[0] : text, - textState.textAlign || defaultTextAlign - ); + // See: https://github.com/openlayers/openlayers/issues/13481 + const align = textState.justify + ? TEXT_ALIGN[textState.justify] + : horizontalTextAlign( + Array.isArray(text) ? text[0] : text, + textState.textAlign || defaultTextAlign + ); const strokeWidth = strokeKey && strokeState.lineWidth ? strokeState.lineWidth : 0; diff --git a/src/ol/render/canvas/Immediate.js b/src/ol/render/canvas/Immediate.js index ab7a55397a..96e8a0261f 100644 --- a/src/ol/render/canvas/Immediate.js +++ b/src/ol/render/canvas/Immediate.js @@ -946,6 +946,7 @@ class CanvasImmediateRenderer extends VectorContext { const textAlign = textState.textAlign ? textState.textAlign : defaultTextAlign; + // Ignore justification here, since rich-text and also `'\n'` make less sense for line placement. if (!contextTextState) { context.font = textState.font; context.textAlign = /** @type {CanvasTextAlign} */ (textAlign); diff --git a/src/ol/render/canvas/TextBuilder.js b/src/ol/render/canvas/TextBuilder.js index b7bb31708e..73aa96553d 100644 --- a/src/ol/render/canvas/TextBuilder.js +++ b/src/ol/render/canvas/TextBuilder.js @@ -211,6 +211,7 @@ class CanvasTextBuilder extends CanvasBuilder { } this.beginGeometry(geometry, feature); const textAlign = textState.textAlign; + // Ignore justification here, since rich-text and also `'\n'` make less sense for line placement. let flatOffset = 0; let flatEnd; for (let o = 0, oo = ends.length; o < oo; ++o) { @@ -449,6 +450,7 @@ class CanvasTextBuilder extends CanvasBuilder { this.textStates[textKey] = { font: textState.font, textAlign: textState.textAlign || defaultTextAlign, + justify: textState.justify, textBaseline: textState.textBaseline || defaultTextBaseline, scale: textState.scale, }; @@ -581,6 +583,7 @@ class CanvasTextBuilder extends CanvasBuilder { textState.maxAngle = textStyle.getMaxAngle(); textState.placement = textStyle.getPlacement(); textState.textAlign = textStyle.getTextAlign(); + textState.justify = textStyle.getJustify(); textState.textBaseline = textStyle.getTextBaseline() || defaultTextBaseline; textState.backgroundFill = textStyle.getBackgroundFill(); @@ -617,6 +620,7 @@ class CanvasTextBuilder extends CanvasBuilder { textState.font + textState.scale + (textState.textAlign || '?') + + (textState.justify || '?') + (textState.textBaseline || '?'); this.fillKey_ = fillState ? typeof fillState.fillStyle == 'string' From e00e3a7b8ea111aecf5709900e9e62b52bf45b3d Mon Sep 17 00:00:00 2001 From: Denis <51781722+rycgar@users.noreply.github.com> Date: Tue, 12 Apr 2022 19:03:25 +0200 Subject: [PATCH 4/9] Improve jsDoc for style/Text justify --- src/ol/style/Text.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/ol/style/Text.js b/src/ol/style/Text.js index 850eaa90f3..9acfd2a055 100644 --- a/src/ol/style/Text.js +++ b/src/ol/style/Text.js @@ -38,6 +38,7 @@ const DEFAULT_FILL_COLOR = '#333'; * @property {string} [justify] Text justification within the text box. * If not set, text is justified towards the `textAlign` anchor. * Otherwise, use options `'left'`, `'center'`, or `'right'` to justify the text within the text box. + * **Note:** `justify` is ignored for immediate rendering and also for `placement: 'line'`. * See: https://github.com/openlayers/openlayers/issues/13481 * @property {string} [textBaseline='middle'] Text base line. Possible values: 'bottom', 'top', 'middle', 'alphabetic', * 'hanging', 'ideographic'. From 1850e16bde32365f1ad6d4b03109d1ab0d58af0b Mon Sep 17 00:00:00 2001 From: Denis <51781722+rycgar@users.noreply.github.com> Date: Wed, 13 Apr 2022 14:11:28 +0200 Subject: [PATCH 5/9] Improve jsDoc and some naming --- examples/vector-labels-justify-text.js | 4 ++-- src/ol/render/canvas/Immediate.js | 3 ++- src/ol/render/canvas/TextBuilder.js | 3 ++- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/examples/vector-labels-justify-text.js b/examples/vector-labels-justify-text.js index c752859d0a..f32b28e10e 100644 --- a/examples/vector-labels-justify-text.js +++ b/examples/vector-labels-justify-text.js @@ -59,7 +59,7 @@ const features = [ }, ]; -function createStyleFunction({textAlign, justify}) { +function createStyle({textAlign, justify}) { return new Style({ image: new CircleStyle({ radius: 10, @@ -98,7 +98,7 @@ const vectorPoints = new VectorLayer({ const feature = new Feature({ geometry: featureOptions.geometry, }); - feature.setStyle(createStyleFunction(featureOptions)); + feature.setStyle(createStyle(featureOptions)); return feature; }) ), diff --git a/src/ol/render/canvas/Immediate.js b/src/ol/render/canvas/Immediate.js index 96e8a0261f..543afdef10 100644 --- a/src/ol/render/canvas/Immediate.js +++ b/src/ol/render/canvas/Immediate.js @@ -946,7 +946,8 @@ class CanvasImmediateRenderer extends VectorContext { const textAlign = textState.textAlign ? textState.textAlign : defaultTextAlign; - // Ignore justification here, since rich-text and also `'\n'` make less sense for line placement. + // Ignore `textState.justify` here, + // since rich-text is not supported for the immediate rendering API. if (!contextTextState) { context.font = textState.font; context.textAlign = /** @type {CanvasTextAlign} */ (textAlign); diff --git a/src/ol/render/canvas/TextBuilder.js b/src/ol/render/canvas/TextBuilder.js index 73aa96553d..5f23ee3c58 100644 --- a/src/ol/render/canvas/TextBuilder.js +++ b/src/ol/render/canvas/TextBuilder.js @@ -211,7 +211,8 @@ class CanvasTextBuilder extends CanvasBuilder { } this.beginGeometry(geometry, feature); const textAlign = textState.textAlign; - // Ignore justification here, since rich-text and also `'\n'` make less sense for line placement. + // Ignore `textState.justify` here, + // since rich-text and also `'\n'` make less sense for line placement. let flatOffset = 0; let flatEnd; for (let o = 0, oo = ends.length; o < oo; ++o) { From 359512c6b21f56e61b38005dcc6cf539d8881c45 Mon Sep 17 00:00:00 2001 From: Denis <51781722+rycgar@users.noreply.github.com> Date: Wed, 13 Apr 2022 15:35:52 +0200 Subject: [PATCH 6/9] Add test for text justification within the text-box See: https://github.com/openlayers/openlayers/issues/13481 --- .../rich-text-justify-style/expected.png | Bin 0 -> 19428 bytes .../cases/rich-text-justify-style/main.js | 133 ++++++++++++++++++ 2 files changed, 133 insertions(+) create mode 100644 test/rendering/cases/rich-text-justify-style/expected.png create mode 100644 test/rendering/cases/rich-text-justify-style/main.js diff --git a/test/rendering/cases/rich-text-justify-style/expected.png b/test/rendering/cases/rich-text-justify-style/expected.png new file mode 100644 index 0000000000000000000000000000000000000000..57c203f669cd998b3b8cd3584b088bc1924735d6 GIT binary patch literal 19428 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 Date: Thu, 14 Apr 2022 08:14:47 +0200 Subject: [PATCH 7/9] Use reference image from CI --- .../rich-text-justify-style/expected.png | Bin 19428 -> 13984 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/test/rendering/cases/rich-text-justify-style/expected.png b/test/rendering/cases/rich-text-justify-style/expected.png index 57c203f669cd998b3b8cd3584b088bc1924735d6..89d3b9b1538bce7c4c8de0b882eebd19734b1969 100644 GIT binary patch literal 13984 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 Date: Thu, 14 Apr 2022 13:06:49 +0200 Subject: [PATCH 8/9] Fix review for text justify --- examples/vector-labels-justify-text.html | 6 ++---- src/ol/render/canvas/Executor.js | 1 - src/ol/render/canvas/Immediate.js | 2 -- src/ol/render/canvas/TextBuilder.js | 3 +-- src/ol/style/Text.js | 1 - 5 files changed, 3 insertions(+), 10 deletions(-) diff --git a/examples/vector-labels-justify-text.html b/examples/vector-labels-justify-text.html index 0047326081..ce4d261c97 100644 --- a/examples/vector-labels-justify-text.html +++ b/examples/vector-labels-justify-text.html @@ -5,10 +5,8 @@ shortdesc: Example of text justification within a label. docs: > This example showcases how the text can be justified within the label box. By default, the text is justified according to the `textAlign` option. - However, this option justifies the label itself according to the setting. - If one wants to change this behavior, it is possible to use the `justify` text style option. - For more information, see the discussion: - https://github.com/openlayers/openlayers/issues/13481 + However, this option justifies also the label itself according to `textAlign` setting. + To decouple the label placement from text placement (within the label box) use `justify`. tags: "vector, openstreetmap, label, rich-text" ---
diff --git a/src/ol/render/canvas/Executor.js b/src/ol/render/canvas/Executor.js index a5793d55b2..b424dfb7bd 100644 --- a/src/ol/render/canvas/Executor.js +++ b/src/ol/render/canvas/Executor.js @@ -239,7 +239,6 @@ class Executor { textState.scale[1] * pixelRatio, ]; const textIsArray = Array.isArray(text); - // See: https://github.com/openlayers/openlayers/issues/13481 const align = textState.justify ? TEXT_ALIGN[textState.justify] : horizontalTextAlign( diff --git a/src/ol/render/canvas/Immediate.js b/src/ol/render/canvas/Immediate.js index 543afdef10..ab7a55397a 100644 --- a/src/ol/render/canvas/Immediate.js +++ b/src/ol/render/canvas/Immediate.js @@ -946,8 +946,6 @@ class CanvasImmediateRenderer extends VectorContext { const textAlign = textState.textAlign ? textState.textAlign : defaultTextAlign; - // Ignore `textState.justify` here, - // since rich-text is not supported for the immediate rendering API. if (!contextTextState) { context.font = textState.font; context.textAlign = /** @type {CanvasTextAlign} */ (textAlign); diff --git a/src/ol/render/canvas/TextBuilder.js b/src/ol/render/canvas/TextBuilder.js index 5f23ee3c58..3e1bb4a45e 100644 --- a/src/ol/render/canvas/TextBuilder.js +++ b/src/ol/render/canvas/TextBuilder.js @@ -211,8 +211,7 @@ class CanvasTextBuilder extends CanvasBuilder { } this.beginGeometry(geometry, feature); const textAlign = textState.textAlign; - // Ignore `textState.justify` here, - // since rich-text and also `'\n'` make less sense for line placement. + // No `justify` support for line placement. let flatOffset = 0; let flatEnd; for (let o = 0, oo = ends.length; o < oo; ++o) { diff --git a/src/ol/style/Text.js b/src/ol/style/Text.js index 9acfd2a055..1337f88187 100644 --- a/src/ol/style/Text.js +++ b/src/ol/style/Text.js @@ -39,7 +39,6 @@ const DEFAULT_FILL_COLOR = '#333'; * If not set, text is justified towards the `textAlign` anchor. * Otherwise, use options `'left'`, `'center'`, or `'right'` to justify the text within the text box. * **Note:** `justify` is ignored for immediate rendering and also for `placement: 'line'`. - * See: https://github.com/openlayers/openlayers/issues/13481 * @property {string} [textBaseline='middle'] Text base line. Possible values: 'bottom', 'top', 'middle', 'alphabetic', * 'hanging', 'ideographic'. * @property {import("./Fill.js").default} [fill] Fill style. If none is provided, we'll use a dark fill-style (#333). From e8f151543d055b00f71097a89fa8d96002719c03 Mon Sep 17 00:00:00 2001 From: Andreas Hocevar Date: Fri, 15 Apr 2022 13:13:39 +0200 Subject: [PATCH 9/9] Simplify/beautify example --- examples/vector-labels-justify-text.js | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/examples/vector-labels-justify-text.js b/examples/vector-labels-justify-text.js index f32b28e10e..a0dbfd94b3 100644 --- a/examples/vector-labels-justify-text.js +++ b/examples/vector-labels-justify-text.js @@ -67,26 +67,19 @@ function createStyle({textAlign, justify}) { stroke: new Stroke({color: 'red', width: 1}), }), text: new Text({ + font: '16px sans-serif', textAlign, justify, - text: [ - 'long text to emphasize justify', - '', - '\n', - '', - `textAlign: ${textAlign}`, - '', - '\n', - '', - `justify: ${justify}`, - '', - ], + text: + `Justify text inside box\ntextAlign: ${textAlign}` + + (justify ? `\njustify: ${justify}` : ''), fill: new Fill({ color: [255, 255, 255, 1], }), backgroundFill: new Fill({ - color: [168, 50, 153, 0.8], + color: [168, 50, 153, 0.6], }), + padding: [2, 2, 2, 2], }), }); }