Skip to content

Commit

Permalink
Merge pull request #1637 from xkxx/master
Browse files Browse the repository at this point in the history
feat: Add basic support for RTL text direction.
  • Loading branch information
lavrton authored Sep 21, 2023
2 parents 0fe8616 + 6a5fc52 commit 23cbea2
Show file tree
Hide file tree
Showing 3 changed files with 105 additions and 2 deletions.
9 changes: 8 additions & 1 deletion src/Context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,11 +77,13 @@ var CONTEXT_PROPERTIES = [
'shadowBlur',
'shadowOffsetX',
'shadowOffsetY',
'letterSpacing',
'lineCap',
'lineDashOffset',
'lineJoin',
'lineWidth',
'miterLimit',
'direction',
'font',
'textAlign',
'textBaseline',
Expand All @@ -91,6 +93,11 @@ var CONTEXT_PROPERTIES = [
] as const;

const traceArrMax = 100;

interface ExtendedCanvasRenderingContext2D extends CanvasRenderingContext2D {
letterSpacing: string;
}

/**
* Konva wrapper around native 2d canvas context. It has almost the same API of 2d context with some additional functions.
* With core Konva shapes you don't need to use this object. But you will use it if you want to create
Expand Down Expand Up @@ -763,7 +770,7 @@ export class Context {

// supported context properties
type CanvasContextProps = Pick<
CanvasRenderingContext2D,
ExtendedCanvasRenderingContext2D,
(typeof CONTEXT_PROPERTIES)[number]
>;

Expand Down
39 changes: 38 additions & 1 deletion src/shapes/Text.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ export function stringToArray(string: string) {
}

export interface TextConfig extends ShapeConfig {
direction?: string;
text?: string;
fontFamily?: string;
fontSize?: number;
Expand All @@ -41,11 +42,13 @@ export interface TextConfig extends ShapeConfig {
var AUTO = 'auto',
//CANVAS = 'canvas',
CENTER = 'center',
INHERIT = 'inherit',
JUSTIFY = 'justify',
CHANGE_KONVA = 'Change.konva',
CONTEXT_2D = '2d',
DASH = '-',
LEFT = 'left',
LTR = 'ltr',
TEXT = 'text',
TEXT_UPPER = 'Text',
TOP = 'top',
Expand All @@ -55,11 +58,13 @@ var AUTO = 'auto',
PX_SPACE = 'px ',
SPACE = ' ',
RIGHT = 'right',
RTL = 'rtl',
WORD = 'word',
CHAR = 'char',
NONE = 'none',
ELLIPSIS = '…',
ATTR_CHANGE_LIST = [
'direction',
'fontFamily',
'fontSize',
'fontStyle',
Expand Down Expand Up @@ -132,6 +137,7 @@ function checkDefaultFill(config?: TextConfig) {
* @memberof Konva
* @augments Konva.Shape
* @param {Object} config
* @param {String} [config.direction] default is inherit
* @param {String} [config.fontFamily] default is Arial
* @param {Number} [config.fontSize] in pixels. Default is 12
* @param {String} [config.fontStyle] can be 'normal', 'italic', or 'bold', '500' or even 'italic bold'. 'normal' is the default.
Expand Down Expand Up @@ -185,6 +191,7 @@ export class Text extends Shape<TextConfig> {
fontSize = this.fontSize(),
lineHeightPx = this.lineHeight() * fontSize,
verticalAlign = this.verticalAlign(),
direction = this.direction(),
alignY = 0,
align = this.align(),
totalWidth = this.getWidth(),
Expand All @@ -194,19 +201,26 @@ export class Text extends Shape<TextConfig> {
shouldUnderline = textDecoration.indexOf('underline') !== -1,
shouldLineThrough = textDecoration.indexOf('line-through') !== -1,
n;

direction = direction === INHERIT ? context.direction : direction;

var translateY = 0;
var translateY = lineHeightPx / 2;

var lineTranslateX = 0;
var lineTranslateY = 0;

if (direction === RTL) {
context.setAttr('direction', direction);
}

context.setAttr('font', this._getContextFont());

context.setAttr('textBaseline', MIDDLE);

context.setAttr('textAlign', LEFT);


// handle vertical alignment
if (verticalAlign === MIDDLE) {
alignY = (this.getHeight() - textArrLen * lineHeightPx - padding * 2) / 2;
Expand Down Expand Up @@ -282,7 +296,10 @@ export class Text extends Shape<TextConfig> {
context.stroke();
context.restore();
}
if (letterSpacing !== 0 || align === JUSTIFY) {
// As `letterSpacing` isn't supported on Safari, we use this polyfill.
// The exception is for RTL text, which we rely on native as it cannot
// be supported otherwise.
if (direction !== RTL && (letterSpacing !== 0 || align === JUSTIFY)) {
// var words = text.split(' ');
spacesNumber = text.split(' ').length - 1;
var array = stringToArray(text);
Expand All @@ -303,6 +320,9 @@ export class Text extends Shape<TextConfig> {
lineTranslateX += this.measureSize(letter).width + letterSpacing;
}
} else {
if (letterSpacing !== 0) {
context.setAttr('letterSpacing', `${letterSpacing}px`);
}
this._partialTextX = lineTranslateX;
this._partialTextY = translateY + lineTranslateY;
this._partialText = text;
Expand Down Expand Up @@ -615,6 +635,7 @@ export class Text extends Shape<TextConfig> {
return super._useBufferCanvas();
}

direction: GetSet<string, this>;
fontFamily: GetSet<string, this>;
fontSize: GetSet<number, this>;
fontStyle: GetSet<string, this>;
Expand Down Expand Up @@ -682,6 +703,22 @@ Factory.overWriteSetter(Text, 'width', getNumberOrAutoValidator());

Factory.overWriteSetter(Text, 'height', getNumberOrAutoValidator());


/**
* get/set direction
* @name Konva.Text#direction
* @method
* @param {String} direction
* @returns {String}
* @example
* // get direction
* var direction = text.direction();
*
* // set direction
* text.direction('rtl');
*/
Factory.addGetterSetter(Text, 'direction', INHERIT);

/**
* get/set font family
* @name Konva.Text#fontFamily
Expand Down
59 changes: 59 additions & 0 deletions test/unit/Text-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1654,4 +1654,63 @@ describe('Text', function () {

assert.equal(layer.getContext().getTrace(), trace);
});

it('sets ltr text direction', function () {
var stage = addStage();
var layer = new Konva.Layer();

stage.add(layer);
var text = new Konva.Text({
text: 'ltr text',
direction: 'ltr',
});

layer.add(text);
layer.draw();

var trace =
'clearRect(0,0,578,200);clearRect(0,0,578,200);save();transform(1,0,0,1,0,0);font=normal normal 12px Arial;textBaseline=middle;textAlign=left;translate(0,0);save();fillStyle=black;fillText(ltr text,0,6);restore();restore();';

assert.equal(layer.getContext().getTrace(), trace);
});


it('sets rtl text direction', function () {
var stage = addStage();
var layer = new Konva.Layer();

stage.add(layer);
var text = new Konva.Text({
text: 'rtl text',
direction: 'rtl',
});

layer.add(text);
layer.draw();

var trace =
'clearRect(0,0,578,200);clearRect(0,0,578,200);save();transform(1,0,0,1,0,0);direction=rtl;font=normal normal 12px Arial;textBaseline=middle;textAlign=left;translate(0,0);save();fillStyle=black;fillText(rtl text,0,6);restore();restore();';

assert.equal(layer.getContext().getTrace(), trace);
});

it('sets rtl text direction with letterSpacing', function () {
var stage = addStage();
var layer = new Konva.Layer();

stage.add(layer);
var text = new Konva.Text({
text: 'rtl text',
direction: 'rtl',
letterSpacing: 2,
});

layer.add(text);
layer.draw();

var trace =
'clearRect(0,0,578,200);clearRect(0,0,578,200);save();transform(1,0,0,1,0,0);direction=rtl;font=normal normal 12px Arial;textBaseline=middle;textAlign=left;translate(0,0);save();letterSpacing=2px;fillStyle=black;fillText(rtl text,0,6);restore();restore();';

assert.equal(layer.getContext().getTrace(), trace);
});
});

0 comments on commit 23cbea2

Please sign in to comment.