Search code examples
javascripthtml5-canvasfabricjsdraw

How can I prevent both vertical and horizontal stretching of contained text while resizing text-based objects in Fabric.js?


I want to be able to scale text-based objects (for example with classes and subclasses of IText, Textbox) without stretching the text inside of the object. The interaction of scaling and moving is on user-side (UI), not programmatically (I am working on a drawing editor).

enter image description here

The behaviour I am looking for is similar to the one in the sticky notes apps: You can scale the paper but this action does not scale your text too.

I have already checked this, but this is only for horizontal prevention: Fabric.js How to resize IText horizontally without stretching the text

This is neither what I want/mean: Fabric.js : How to set a custom size to Text or IText?

I know that a scaling factor different than 1 implies the stretching of the inner text, and that by changing the width and height I can resize the object while keeping the text unscaled, so I tried updating these during scaling using events listeners.

I tried many combinations of the IText,Textbox with some scaling events, like this one:

fbtext.on('scaling', function() {
                      this.set({
                        width : this.width  * this.scaleX,
                        height: this.height * this.scaleY,
                        scaleX: 1,
                        scaleY: 1,
                      });
                    });

I also tried this with Textbox:

fbtext.on('scaling', function() {
                      this.set({
                        height: this.height * this.scaleY,
                      });
                    });

But nothing worked so far. I am out of ideas.


Solution

  • var canvas = new fabric.Canvas('mycanvas');
    
    let textbox = new fabric.Textbox("Sample text", {
       left: 100,
       top: 100
    });
    
    let lastHeight;
    
    const updateTextSize = () => {	
    
      const controlPoint = textbox.__corner;
    
      //mr and ml are the only controlPoints that dont modify textbox height
      if( controlPoint && controlPoint != "mr" && controlPoint != "ml"){
     	   lastHeight =  textbox.height * textbox.scaleY;			
      }
    
      textbox.set({		
      	 height: lastHeight || textbox.height,
    	 scaleY:1				
      });
      
      canvas.renderAll();
    };
    		
    	
    textbox.on('scaling', updateTextSize );
    textbox.on('editing:entered', updateTextSize);
    canvas.on('text:changed', updateTextSize);
      
    canvas.add(textbox);
    canvas {
        border: 1px solid black;
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/3.3.2/fabric.min.js"></script>
    <canvas id="mycanvas" width="400" height="400"></canvas>

    Here is a code sample that will let you modify the "sticky note size" without streching out the text