Search code examples
javascriptcsscanvasfabricjs

fabric-js textBakgroundColor not covering whole text when changing object property


I am using fabric-js for creating templates on canvas. but facing a wired issue.

I have added a Textbox object to canvas, when i am trying to change fontFamily and fontWeight of Textbox, sometimes the textBackgroundColor not cover the whole text.

enter image description here

I have created a jsfiddle to showcase this issue.

Steps to reproduce:

  • Select textbox object, change fontFamily from Merriweather to Lato
  • Then change fontWeight from normal to bold

Note: it is happening for specific fonts like Merriweather not for all, Also sometimes it works but not everytime.


Solution

  • This happen when the fonts are not properly loaded. The fabricJs request the font bold, that is not ready, not even the regular one is ready, and render with a fallback. When the font is ready, the font measurement is already done, and is wrong.

    You have to properly load the fonts with a font loader. Check for fontFaceObeserver, is really easy to use.

    In the snippet below i used just a very hacky setTimeout and 2 paragraph to force the browser to load the font in advance.

    var canvas = new fabric.Canvas('canvas');
    setTimeout(function() {
    text = new fabric.Textbox("Click here twice to edit", {
      width: 300,
      fontSize: 25,
      fontFamily: 'Merriweather',
      textAlign: 'center',
      textBackgroundColor : '#000',
      fill: '#ffc107',
    });
    canvas.add(text);
    
    window.toggleBoldText = function() {
      var obj = canvas.getActiveObject();
      if(obj){
        if (obj.get('fontWeight') == 'normal'){
          obj.set('fontWeight', 'bold');
        }else{
          obj.set('fontWeight', 'normal');
        }
      	canvas.renderAll();
      }else{
        alert("select text object to add font weight");
      }
    }
    
    window.toggleFontFamily = function() {
      var obj = canvas.getActiveObject();
      if(obj){
       if (obj.get('fontFamily') == 'Merriweather'){
          obj.set('fontFamily', 'Lato');
        }else{
          obj.set('fontFamily', 'Merriweather');
        }
        canvas.renderAll();
      }else{
        alert("select text object to add font family");
      }  
    }
    
    }, 3000);
    @import url(//fonts.googleapis.com/css?family=Merriweather%7CLato);
    
    .canvas-container {
      border: 1px dotted #ccc;
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.7.22/fabric.js"></script>
    <button onclick="toggleFontFamily()">toggle font family</button>
    <button onclick="toggleBoldText()">toggle bold</button>
    <span style="font-family: Merriweather; font-weight: bold;">Merri bold</span><span style="font-family: Merriweather; font-weight: normal;">Merri normal</span>
    <canvas width="500" height="300" id="canvas"></canvas>