1

Hi I have some troubles with text on canvas. I have several inputs type text and for each of them, I need to create canvas with their texts. When inputs have default texts, texts are not shown on canvas the first time. I need to refresh before seeing texts in firefox (and texts with fonts applied in chrome incognito mode). I try to do solutions I found here :Drawing image on canvas in firefox on first load or reload with ctrl+f5 does not work or here: Firefox won't draw to canvas on first visit but I cannot make them work. Any idea for me? thanks

Here is my simplified code:

(function( $ ) {
'use strict';

$(document).ready(function () {

    if(typeof(pgc)!='undefined'){
        somefunction(); //call this first because canvas need #preview width and height.
        setTimeout(create_pgc_text_container, 200, "non ajax");
    }


    function create_pgc_text_container(mode){
        console.log(mode);
        $('[id$="-field"]').each(function ()
        {
            var id=$(this).attr('id');
            var field_settings=pgc.text_settings[id];
            var field_datas=$.parseJSON(field_settings);
            var angle="rotate("+field_datas.angle+"deg)";
            $("#text_panel").append('<canvas id="'+field_datas.container+'" class="text_field jtextfill" style="font-size:'+field_datas.size+'px;top:'+field_datas.top+'%;transform:'+angle+';left:'+field_datas.left+'%;"><span></span></div>');

            var text = $(this).val();
            var current_field_id = $(this).attr('id');
            var current_color = $('#'+current_field_id).parent('.textfield-box').parent('.pgc-single-option-wrap.textfield').find('.pgc-textfield .pgc-textfield-color [data-field]').data('color');
            var current_font = $('#'+current_field_id).parent('.textfield-box').parent('.pgc-single-option-wrap.textfield').find('.pgc-textfield .pgc-textfield-font .font-selector[data-field]').val();
            var current_font_link = $('#'+current_field_id).parent('.textfield-box').parent('.pgc-single-option-wrap.textfield').find('.pgc-textfield .pgc-textfield-font .font-selector option:first').data('font');

            var image = new Image;
            image.src = current_font_link;
            $.when(current_font_link.load)
            .done(function () {
                image.onerror = function() {
                    console.log(current_font_link);
                    add_text_on_preview(text,current_field_id, current_font, current_color);       
                };
            });

            add_text_on_preview(text,current_field_id, current_font, current_color);
            // call again because some troubles in firefox loading first time.

            somefunction();

        });          
    }

    function add_text_on_preview(text, field_id, font, color){
        font = font || '';
        color = color || '';
        var field_settings = pgc.text_settings[field_id];
        var field_datas = $.parseJSON(field_settings);
        //console.log(field_datas.default_font);

        var mycanvas = $('#'+field_datas.container);
        mycanvas[0].width = $('#preview').width();
        mycanvas[0].height = $('#preview').height();

        var ctx = mycanvas[0].getContext('2d');

        var fontfamily = function() {
            var field_font;
            if (font == '') {
                if ( field_datas.default_font !== null ) {
                    field_font = field_datas.default_font;
                } else {
                    field_font = ' sans-serif';
                }
            }
            else
                field_font = font;

            if ( field_font.indexOf("://") != -1 ) {
                //console.log('found');
                fontUrlArray = field_font.split("=");
                if ( fontUrlArray.length >= 1 ) {
                    return fontUrlArray[1].split('+').join(' ');
                }
            }
            else {
                //console.log('not found', field_datas.font);
                return field_font;
            }

        }();

        ctx.clearRect(0, 0, mycanvas[0].width, mycanvas[0].height);

        field_datas.size = ( field_datas.size !== null && ( field_datas.size !== undefined && ( field_datas.size !== '' ) ) ) ? field_datas.size : 12 ; 
        //ctx.font = field_datas.size + 'px ' + font;
        ctx.font = field_datas.size + 'px ' + fontfamily;
        //console.log(ctx.font);

        if (color == '') 
            ctx.fillStyle = field_datas.default_color;
        else
            ctx.fillStyle = color;

        ctx.textBaseline = 'middle';
        ctx.textAlign = field_datas.text_align; 

        var positionTopText = ($('#preview').height() * field_datas.top)/100;
        var positionLeftText = ($('#preview').width() * field_datas.left)/100;
        //console.log(positionLeftText, positionTopText);

        ctx.fillText(text, positionLeftText, positionTopText);
    }


});

})( jQuery );
Cutis
  • 528
  • 4
  • 18

2 Answers2

1

Finally I use webfont.js and some jquery promises. But I was forced to check more than one time if all dom element (tests) are loaded. This following waitForEl function , i found it here

     var waitForEl = function(selector, callback) {
      if (jQuery(selector).length) {
        callback();
      } else {
        setTimeout(function() {
          waitForEl(selector, callback);
        }, 100);
      }
    };

    WebFont.load({
        custom: {
            families: customFonts
        },
        google: {
            families: googleFonts
        },
        active: function() {
            console.log('webfonts loaded');
            waitForEl(inputs, function() {
              // here add my text element to canvas
            });
        },
    });
Cutis
  • 528
  • 4
  • 18
0

I've had this issue before. It's the same scenario with external fonts that it is with images, you are calling it before they load. I saw this hacky solution somewhere and it worked for me (still trying to find the source so I can link it here).

Do something like this:

HTML: <p id="loadMe">Must include Text</p>

(Put the above tag before <script> and <canvas>)

CSS:

@font-face {
  /*Define the font here*/
}

#loadMe {
  font-family: [Insert whatever it is];
}

If the font loads on canvas first try, then you can experiment with how to hide the loader element! You may need to use style.fontFamily in your js file to ensure that it doesn't re-load the font from the same location.

dandeto
  • 567
  • 4
  • 12
  • Finally I use webfont.js and some jquery promises. But I was forced to check more than one time if all dom element (tests) are loaded. – Cutis Jun 26 '18 at 13:39