【问题标题】:canvas loadFromJson does not apply font-family画布 loadFromJson 不适用字体系列
【发布时间】:2018-03-28 02:24:37
【问题描述】:

我正在使用下面的代码来渲染谷歌字体并更新画布:

    /* on change of font load the preview as well as canvas */
    $('#font').on('change', function () {
        $('.font_preview').show();
        var font_family = $(this).val();

        $('.font_preview').css('font-family', font_family, 14);
        $('.font_preview').html(font_family,'');
        load_web_font([font_family],'.font_preview',font_family,1);
    });

    function load_web_font(font_family, preview_div,font_family_text,preview_text) {
        var grep_font = jQuery.grep(font_family, function (n, i) {
            return ( n );
        });
        if (grep_font.length > 0) {
            var preview_text;
            if (preview_div) {
                preview_text = $(preview_div).text();
            }
            WebFont.load({
                google: {
                    families: font_family
                },
                fontloading: function (familyName, fvd) {
                    if (preview_div) {
                        if(preview_text==1)
                        {
                            $(preview_div).text('font loading ... ');
                        }
                    }

                },
                fontactive: function (familyName, fvd) {
                    if (preview_div) {
                        if(preview_text==1)
                        {
                            $(preview_div).text(preview_text);
                        }
                        load_font_on_canvas(font_family_text);
                    }
                },
                timeout: 10000
            });
        }
    }

     //Load Font on Canvas
    function load_font_on_canvas(font_style)
    {
        var font_style = font_style;
        if(font_style=='')
        {
            alert('Please select a Font Style');
            return false;
        }
        var tObj = canvas.getActiveObject();
        //Check that text is selected
        if(tObj==undefined)
        {
            alert('Please select a Text');
            return false;
        }
        tObj.set({
            fontFamily: font_style
        });
        canvas.renderAll();
    }

现在,我将画布数据作为 json 存储在数据库中。因此,在那之后,当用户尝试编辑该画布时,我将使用以下代码渲染画布:

    if(is_update==1) // Update then load the card
    {
        // parse the data into the canvas
        canvas1.loadFromJSON(front_side_object);
        // re-render the canvas
        canvas1.renderAll();

        canvas2.loadFromJSON(back_side_object);
        canvas2.renderAll();
    }

所以画布正在加载,但不是用户选择的字体。所以我尝试了下面的代码来用谷歌字体更新画布,但它不起作用

    //Grab each google fonts
    var all_fonts = [];
    $('#font option').each(function(){
        var font_family = $(this).val();
        //all_fonts +=  font_family + '|';
        if(font_family!='')
        {
            all_fonts.push(font_family);
        }
    });
    load_all_web_font(all_fonts);

    function load_all_web_font(all_fonts)
    {
        var grep_font = jQuery.grep(all_fonts, function (n, i) {
            return ( n );
        });
        WebFont.load({
            google: {
                families: all_fonts
            },
            fontloading: function (familyName, fvd) {
                //Do Something
            },
            fontactive: function (familyName, fvd) {
                //1st Try rerender canvas again after fonts is loaded
                //Do SOmething
                canvas1.loadFromJSON(front_side_object);
                // re-render the canvas
                canvas1.renderAll();

                canvas2.loadFromJSON($model->back_side_object);
                canvas2.renderAll();

                //Get the text and rerender the canvas
                canvas1.getObjects().filter(function(o) {
                    if (o.get('type') === 'text') {
                        console.log(o.get);
                        canvas1.renderAll();
                    }
                });
                canvas2.getObjects().filter(function(o) {
                    if (o.get('type') === 'text') {
                        canvas2.renderAll();
                    }
                });
            },
            timeout: 10000
        });
    }

【问题讨论】:

  • 您必须在 loadFromJson 之前检查是否下载了 google 字体。你可以在加载完谷歌字体后再次调用renderAll。
  • @artgb 我在 fontactive: function (familyName, fvd) { event.加载字体后,我将调用 renderAll。
  • 请制作 jsfiddle,很难期待当前的状态。
  • 这里有一个自定义字体加载演示:fabricjs.com/loadfonts 它使用 FontFaceObserver github.com/bramstein/fontfaceobserver

标签: javascript jquery canvas fabricjs


【解决方案1】:

我知道这是一个老问题,但我遇到了同样的问题。你需要做的是将Text的dirty属性设置为true,然后调用canvas.renderAll()

我使用的一个示例(在 TypeScript 中)是在加载 JSON 后调用我的函数 rerenderWhenAFontisLoaded

import FontFaceObserver from 'fontfaceobserver';

const myFonts = ['Pacifico', 'VT323', 'Quicksand'];

const rerenderWhenAFontIsLoaded = (): void => {
    let timer: NodeJS.Timeout | null = null;
    myFonts.forEach((font) => {
        new FontFaceObserver(fontName)
        .load()
        .then(() => {
            if (timer) {
                clearTimeout(timer);
                timer = null;
            }
            timer = setTimeout(() => {
                const [fonts] = getObjectsOfTypes(canvas, [['textbox', 'i-text', 'text']]);
                fonts.forEach((font) => {
                    font.dirty = true;
                });
                canvas.requestRenderAll();
            }, 1000);
        })
        .catch(() => {
            // dont care
        });
    });
};

/**
 * An recursive function to return an array of objects as defined in the types argument.
 * @param object Either an canvas or a group object
 * @param types: like [['polygon'], [['i-text', 'textbox', 'text']]
 * @returns array of fabric.Objects in the same order as you defined in the types argument.
 */
const getObjectsOfTypes = (object: fabric.Object | fabric.Canvas, types: string[][]): fabric.Object[][] => {
    const result: fabric.Object[][] = [];

    for (let i = 0; i < types.length; i++) {
        result.push([]);
        if (types[i].includes((object as fabric.Object).type!)) {
            result[i].push(object as fabric.Object);
            break;
        }
    }

    // Check if we can call getObjects, then we either know it's the canvas or another group.
    if (typeof (object as fabric.Group).getObjects === 'function') {
        (object as fabric.Group | fabric.Canvas).getObjects().forEach((object) => {
            const moreRelevantObjects = this.getObjectsOfType(object, types);
            moreRelevantObjects.forEach((objects, i) => {
                result[i].push(...objects);
            });
        });
    }

    return result;
};



【讨论】:

    【解决方案2】:

    诀窍是先过滤所有文本对象,然后加载字体,然后渲染画布。

    这对我有用

     let fonts = this.canvas
                .getObjects()
                .filter((o: any) => o.get('type') === 'textbox')
                .map((o: any) => o.fontFamily)
    
          WebFontLoader.load({
            google: {
              families: [...fonts],
            },
            active: () => {
              this.canvas.renderAll()
            },
          })
    

    【讨论】:

      猜你喜欢
      • 2019-05-11
      • 1970-01-01
      • 1970-01-01
      • 2018-06-09
      • 2015-03-14
      • 2015-12-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多