Fix emoji rendering with letterSpacing. close #1642

This commit is contained in:
Anton Lavrevov 2024-12-16 19:46:41 -05:00
parent cbbc9921b6
commit 855e7fa40d
3 changed files with 20 additions and 12 deletions

View File

@ -3,6 +3,10 @@
All notable changes to this project will be documented in this file. All notable changes to this project will be documented in this file.
This project adheres to [Semantic Versioning](http://semver.org/). This project adheres to [Semantic Versioning](http://semver.org/).
## 9.3.18 (2024-12-17) (unreleased)
- Fix emoji rendering with letterSpacing
## 9.3.17 (2024-12-02) (unreleased) ## 9.3.17 (2024-12-02) (unreleased)
- Fix `Arrow.getClientRect()` - Fix `Arrow.getClientRect()`

View File

@ -16,14 +16,15 @@ import { GetSet } from '../types';
export function stringToArray(string: string): string[] { export function stringToArray(string: string): string[] {
// Use Unicode-aware splitting // Use Unicode-aware splitting
return [...string].reduce((acc, char, index, array) => { return [...string].reduce((acc, char, index, array) => {
// Handle emoji sequences (including ZWJ sequences) // Handle emoji with skin tone modifiers and ZWJ sequences
if ( if (/\p{Emoji}/u.test(char)) {
/\p{Emoji_Modifier_Base}\p{Emoji_Modifier}?(?:\u200D\p{Emoji_Presentation})+/u.test( if (acc.length > 0 && /\p{Emoji}/u.test(acc[acc.length - 1])) {
char // Combine with previous emoji if it's part of a sequence
) acc[acc.length - 1] += char;
) { } else {
acc.push(char); acc.push(char);
} }
}
// Handle regional indicator symbols (flags) // Handle regional indicator symbols (flags)
else if ( else if (
/\p{Regional_Indicator}{2}/u.test(char + (array[index + 1] || '')) /\p{Regional_Indicator}{2}/u.test(char + (array[index + 1] || ''))
@ -383,7 +384,8 @@ export class Text extends Shape<TextConfig> {
return isAuto ? this.getTextWidth() + this.padding() * 2 : this.attrs.width; return isAuto ? this.getTextWidth() + this.padding() * 2 : this.attrs.width;
} }
getHeight() { getHeight() {
const isAuto = this.attrs.height === AUTO || this.attrs.height === undefined; const isAuto =
this.attrs.height === AUTO || this.attrs.height === undefined;
return isAuto return isAuto
? this.fontSize() * this.textArr.length * this.lineHeight() + ? this.fontSize() * this.textArr.length * this.lineHeight() +
this.padding() * 2 this.padding() * 2
@ -501,7 +503,9 @@ export class Text extends Shape<TextConfig> {
this.textArr = []; this.textArr = [];
getDummyContext().font = this._getContextFont(); getDummyContext().font = this._getContextFont();
const additionalWidth = shouldAddEllipsis ? this._getTextWidth(ELLIPSIS) : 0; const additionalWidth = shouldAddEllipsis
? this._getTextWidth(ELLIPSIS)
: 0;
for (let i = 0, max = lines.length; i < max; ++i) { for (let i = 0, max = lines.length; i < max; ++i) {
let line = lines[i]; let line = lines[i];

View File

@ -146,7 +146,7 @@ describe('Text', function () {
var text = new Konva.Text({ var text = new Konva.Text({
x: 10, x: 10,
y: 10, y: 10,
text: '😬', text: '😬👧🏿',
fontSize: 50, fontSize: 50,
letterSpacing: 1, letterSpacing: 1,
}); });
@ -159,7 +159,7 @@ describe('Text', function () {
context.textBaseline = 'middle'; context.textBaseline = 'middle';
context.font = 'normal normal 50px Arial'; context.font = 'normal normal 50px Arial';
context.fillStyle = 'darkgrey'; context.fillStyle = 'darkgrey';
context.fillText('😬', 10, 10 + 25); context.fillText('😬👧🏿', 10, 10 + 25);
compareLayerAndCanvas(layer, canvas, 254); compareLayerAndCanvas(layer, canvas, 254);
}); });