konvajs / konva

Konva.js is an HTML5 Canvas JavaScript framework that extends the 2d context by enabling canvas interactivity for desktop and mobile applications.
http://konvajs.org/
Other
11.53k stars 924 forks source link

Inconsistent Konva.Text width (Browser vs NodeJS) #1599

Closed faizulhaque closed 1 year ago

faizulhaque commented 1 year ago

Thank you for submitting an issue!

Here is the demo link on the web: https://codesandbox.io/s/peaceful-bhaskara-c3rl4y?file=/src/index.js

image If you observe Text and blue line, it's almost matched interms of width.

However, I tried to run the same code on server, It's going beyond the width.

Here is the server code:

const Konva = require('konva');
const { registerFont } = require('canvas');

registerFont('./fonts/PlayFair/PlayfairDisplay-Regular.ttf', { family: "'Playfair Display', serif", weight: "400", style: "normal" })
registerFont('./fonts/PlayFair/PlayfairDisplay-Italic.ttf', { family: "'Playfair Display', serif", weight: "400", style: "italic" })
registerFont('./fonts/PlayFair/PlayfairDisplay-Bold.ttf', { family: "'Playfair Display', serif", weight: "700", style: "normal" })

const fs = require('fs');

const fontFamily = "'Playfair Display', serif";
const fontSize = 15.599999999999973;
const fontStyle = "400";
Konva.pixelRatio = 2;
const stageWidth = 794;
const stageHeight = 1122;
const padding = 24;
const stage = new Konva.Stage({
  width: stageWidth,
  height: stageHeight
});

const layer = new Konva.Layer({});
const rectWidth = stageWidth - padding - padding - padding;
let rect = new Konva.Rect({
  x: padding,
  y: 100,
  width: rectWidth,
  height: 1,
  fill: "white"
});
const line =
  "I work with mainly brides, so if you are a bride getting married, I am who you want making your dress";
const text = new Konva.Text({
  text: line,
  fontFamily: fontFamily,
  fontSize: fontSize,
  fontStyle: fontStyle,
  x: padding,
  fill: 'white',
  y: 110
});
let spaceTxtWidth = new Konva.Text({
  x: 0,
  y: 0,
  text: " ",
  fontFamily: fontFamily,
  fontSize: fontSize,
  fontStyle: fontStyle
}).width();
let spacesRequired = (rectWidth - text.width()) / spaceTxtWidth;
let repeatCount = 1;
while (spacesRequired > 1) {
  repeatCount++;
  let lineCharArray = line.split("");
  for (let i = 0; i < lineCharArray.length; i++) {
    if (lineCharArray[i].indexOf(" ") > -1) {
      lineCharArray[i] = " ".repeat(repeatCount);
      spacesRequired -= 1;
    }
    if (spacesRequired < 1) {
      text.setAttrs({
        text: lineCharArray.join("")
      });
      break;
    }
  }
}
if (text.width() !== rectWidth) {
  let spce = (rectWidth - text.width()) / text.text().split("").length;
  text.setAttrs({
    letterSpacing: spce
  });
}
console.log(`rectWidth: ${rectWidth}, lineWidth: ${text.width()}`);
layer.add(text);
layer.add(rect);
stage.add(layer);

let imageData = stage.toDataURL({
  mimeType: "image/png",
  width: stageWidth,
  height: stageHeight,
});
const base64Data = imageData.replace(/^data:image\/png;base64,/, "");
fs.writeFileSync(`test.png`, base64Data, { encoding: 'base64' });
console.log(`done`);

Here is the server snapshot: image

KonvaJS version: Frontend: "konva": "9.0.1",

NodeJS: (version: 14.19.1) "konva": "9.0.1", "canvas": "2.11.2"

Can anyone help understand Is this a bug? or I am missing something in the code (browser vs nodejs)?

Thanks in Advance, cc: @lavrton

lavrton commented 1 year ago

There is nothing much I can do from Konva side. Different render engines may produce different results.

Even different browsers, like Chrome vs Firefox vs Safari, may produce different results.

You may try to reduce the font size manually a bit to match the required size.

faizulhaque commented 1 year ago

You may try to reduce the font size manually a bit to match the required size.

Well, Yes, however, it should be done programmatically, but the challenge is even after applying the letterSpacing the value of text.width() is still less than the value of rectWidth but visually it's going beyond the line.

So unable to find (programmatically) either the text is going beyond the area width. Any tip/clue?

lavrton commented 1 year ago

Probably need to report in canvas library.