Fabric.js: On scaling canvas: hiddenTextarea moves outside of canvas boundaries, forcing the viewport to change

Created on 15 May 2019  路  4Comments  路  Source: fabricjs/fabric.js

I appreciate that this is a very complicated issue, and corner case for advanced users. This issue is opened for the sole purpose of me wanting to contribute back to this project, with a canvas scaling functionality.

The problem is a classical HTML5 Canvas problem, where you want to have a certain pixel ratio on the exported image from the canvas (let's say 1600x900 px), but we want to display the canvas on a smaller area (900x450 px). One solution is to have the canvas in full scale (1900x900px) and then use the CSS transform property to scale it to any other size.

Doing this with Fabric works fine, until you add anything with a text input (Text or Textbox) where the hiddenTextarea won't be scaled and therefore pushes outside of the boundaries (and potentially the viewport).

Two questions:

  1. @asturur Is there any reasons why the hiddenTextarea are not always styled to appear at top: 0 left:0? If (2) is implemented, we can continue positioning the hiddenTextarea as now, and just use a scaling prop to adjust the position. But yet again, I'm thinking this might be overkill and top: 0, left: 0 might just be the most reliable solution.
  1. Are we interested as a community to add a function where we can input an exportHeight, and exportWidth into the canvasOptions to get a given size on the exported image without any loss of quality? If yes, then I'm happy to implement this and send up as a MR.

Most helpful comment

when you make an export, fabric re renders everything on a new bigger canvas. Images will be as much good as the image you loaded if there is space on the canvas.

All 4 comments

So as today there is all the code you need to have this functionality.
My preferred solution is:

var desired_final_dimensions: { width: 20000, height: 14000 };
var my_canvas_is_big_just: { width: 90, height: 50 }; // notice aspect ratio can be different
var my_zoom_value = fabric.util.findScaleToFit(desired_final_dimensions, my_canvas_is_big_just);
canvas.setZoom(my_zoom_value);

At this point you can work with left and top in the range of 20000, 14000 ( if you have a logic that requires to know the final dimensions ), you can work on that small canvas and then export with a toDataUrl or toCanvasElement if you need to do more image processing.

You need yo use the multiplier of 1 / my_zoom_value of course and you need to set the width/height to something i do not recall now.

We can argue that being able to set the final dimensions in the export directly would be easier for everyone.

To answer your questions too:

  • the hiddenTextarea has to follow the cursor in order to help with macOS long press functionality and also languages that have a dropdown for composition ( some chinese and japanese ime )
  • the 2 can be interesting, if we manage to fit it in the function toCanvasElement, reusing fabric.util.findScaleToFit and with few code that does not clash with the existing options.

I'm with you on your solution, but I can't just avoid thinking that this will degrade images a lot. Having a canvas 90x50 px, with an image filling the whole canvas, wouldn't its bitmap size to the canvas size? And once you then scale up the whole thing, this would then degrade the image?

After this discussion, I'll go ahead and try to find a solution and will push it as a MR :)

when you make an export, fabric re renders everything on a new bigger canvas. Images will be as much good as the image you loaded if there is space on the canvas.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

raichu picture raichu  路  4Comments

zhangzhzh picture zhangzhzh  路  4Comments

bevacqua picture bevacqua  路  4Comments

semiadam picture semiadam  路  3Comments

semiadam picture semiadam  路  3Comments