【问题标题】:Canvas only renders custom webfont on click event with fabric.jsCanvas 仅在使用 fabric.js 的单击事件上呈现自定义 webfont
【发布时间】:2015-05-06 18:31:53
【问题描述】:

我在自定义 webfonts 和 fabric.js 方面一直存在问题。 我的应用程序使用了很多自定义网络字体,我在向画布添加 iText 时对其进行了初始化:

var text = new fabric.IText("My Text", {
    fontFamily: "Some Custom Font Family",
    fontSize: 50,
    top: 0,
    left: 0,
    fill: "#000000"
  });

  canvas.add(text);
  canvas.bringToFront(text);
  canvas.setActiveObject(text);

  canvas.renderAll();

只有当我点击画布上的 iText 并与之交互时才有效。然后,一旦加载了字体,它就不再是问题了。问题是最初和第一次添加 iText。

我研究了很多,来到了这个帖子:

Init loaded text with remote web font in Fabric.js

但这对我没有帮助。那里提供的 jsfiddle 有完全相同的问题:

http://jsfiddle.net/vvL6f/6/

只需使用清除缓存的新浏览器(例如 Chrome CMD+Shift+R)打开此小提琴。打开 fiddle 后,您会看到自定义的 webfont 没有加载,而是在您单击右侧的 iText 时立即加载。

现在,我们该如何解决这个问题?

建议的方法是将 useNative 设置为 false 并让 Cufon 呈现文本,但这不起作用。

我将我的网络字体加载到这样的 CSS 文件中:

@font-face {
    font-family: 'ApolloASM';
    src: url('ApolloASM-webfont.eot');
    src: url('ApolloASM-webfont.eot?#iefix') format('embedded-opentype'),
         url('ApolloASM-webfont.woff2') format('woff2'),
         url('ApolloASM-webfont.woff') format('woff'),
         url('ApolloASM-webfont.ttf') format('truetype'),
         url('ApolloASM-webfont.svg#apollo_asmregular') format('svg');
    font-weight: normal;
    font-style: normal;
}

【问题讨论】:

标签: javascript canvas fabricjs


【解决方案1】:

@Prominic 的答案就快到了。我还有一个使用 Fabric 自定义字体的画布应用程序。我和你一样在 CSS 中加载所有字体。问题是,仅在样式表中声明 @font-face 是不够的。除非在文档中使用,否则浏览器不会请求字体文件。 并且您必须确保在初始化画布之前加载并应用网络字体。这可以通过一些工作来实现,我将在下面用一个例子来说明。缺点是您可能需要预加载您的应用提供给用户的所有字体。


  1. 声明你的网络字体

    在样式表中添加 @font-face 语句。只需确保它已加载到 <head> 部分。让我们用你的例子:
 @font-face {
    font-family: 'ApolloASM';
    src: url('ApolloASM-webfont.eot');
    src: url('ApolloASM-webfont.eot?#iefix') format('embedded-opentype'),
         url('ApolloASM-webfont.woff2') format('woff2'),
         url('ApolloASM-webfont.woff') format('woff'),
         url('ApolloASM-webfont.ttf') format('truetype'),
         url('ApolloASM-webfont.svg#apollo_asmregular') format('svg');
    font-weight: normal;
    font-style: normal;
}

额外提示:如果您在应用程序中使用斜体和/或粗体,如果您希望在不同浏览器中获得一致的结果,建议您同时为这些样式添加字体。例如,Android Browser 4.2 无法计算字体的斜体,并将正常显示。

  1. 强制请求字体文件

正如我上面所说,您需要实际使用 DOM 中的字体来强制加载字体。只需添加一个带有一些文本的 div 并使用您的字体对其进行样式设置就足够了:

<div style="font-family:'ApolloASM'">&nbsp;</div>

额外提示:不要忘记添加斜体和粗体变体

  1. 在 DOM load 事件之后初始化 FabricJS 画布

在浏览器加载字体后,您需要同步画布初始化(或至少添加文本),否则您可能会看到 FOUT 效果(无样式文本的 Flash)。幸运的是,在所有字体文件加载完成之前,浏览器不会触发 load 事件,这可用于安全地将样式文本添加到画布:

window.addEventListener('load', function onLoad() {
    var canvas = new Fabric.Canvas({...});
    var text = new fabric.Text("Web Font Example", {
        left: 200,
        top: 30,
        fontFamily: 'ApolloASM',
        fill: '#000',
        fontSize: 60
    });

    canvas.add(text);
    canvas.renderAll();
})

额外提示:您可以将这些字体 &lt;div&gt; 包装在另一个字体中,并在 DOM load 事件之后将其删除,以避免破坏您可能拥有的任何布局。

【讨论】:

  • 强制请求字体文件,就像一个魅力,非常感谢@Bernardo:D
  • 你让我免于头疼..ty +1
  • 这个解决方案增加了http请求,对seo有轻微的负面影响,如果有90个字体,这将创建90个http请求。
  • 如果我们有很多字体,那就太糟糕了。您能提出其他解决方案吗?
  • @UmeshPatadiya 现在最好使用WebFont Loaderfontactive 回调来触发正确字体的文本渲染。请参阅下面的@Naoyuki 答案。
【解决方案2】:

您可以使用网络字体加载器。

    <script src="//ajax.googleapis.com/ajax/libs/webfont/1.5.18/webfont.js">    </script>
    <script>
    var c = new fabric.Canvas('canvas');
    WebFont.load({
    	google: {
    		families: ['Fredoka One']
    	},
    	active: function() {
            var text = new fabric.IText('Hello world !', {
                fontFamily: 'Fredoka One',
                top: 100,
                left: 100,
                fontSize: 20
            });
    	    c.add(text);
    	},
    });
    </script>

JSFiddle here.

【讨论】:

    【解决方案3】:

    当您的脚本首次渲染画布时,webfont 尚未加载。

    我想说执行此操作的最佳方法是使用 .这将在 DOM 顶部加载字体,以便在浏览器呈现字体时为您的画布脚本准备好字体。这是一个例子。

    https://jsfiddle.net/j47k79e8/1/

    <link href='http://fonts.googleapis.com/css?family=Ranchers' rel='stylesheet' type='text/css'>
    

    如果您仍然想使用 Javascript 方法来加载 webfont,您可以在运行 FabricJS 脚本之前等待文档加载。只需将其包装在文档就绪语句中即可。

    $(document).ready(function(){
      // FabricJS scripts
    });
    

    https://jsfiddle.net/ahxpeu0v/3/

    【讨论】:

    • 好吧,我已经通过它自己的 css 将我的字体加载到了标题中。它们也应该被正确初始化。见 OP,刚刚编辑。将其包装在文档就绪语句中将不起作用,因为我按需调用 addText 函数。
    • 看起来您的字体是自托管的?这是我的另一个想法……尽量减少延迟变量。我的另一个想法是尝试不同的字体。目标只是找出问题所在 - 可能是该特定字体独有的东西?一切对我来说都是正确的。不过,我还没有过多地使用 IText,所以 IText 加载自定义字体的方式可能有一些独特之处。
    【解决方案4】:

    你只需要在插入文本后输入canvas.renderAll();命令,像这样:

    canvas = new fabric.Canvas('c'); 
    var text = new fabric.Text("Web Font Example", {
        left: 200,
        top: 30,
        fontFamily: 'Ranchers',
        fill: '#000',
        fontSize: 60
    });
    
    canvas.add(text);
    canvas.renderAll();
    

    小提琴:http://jsfiddle.net/vvL6f/107/

    【讨论】:

    • 第一次加载时它不起作用,可能是因为字体尚未缓存。
    • 我这样做了 - 请参阅我的原始帖子。 @Shomz 是的,这也是我的怀疑,但我不知道如何在这种情况下解决它。
    • @DonMB,我尝试了一些东西,但最后删除了我的答案,因为所有版本都以某种方式遇到相同的问题。我拒绝使用超时。有人可能会想出一些好东西,请耐心等待。
    • 感谢您的努力。是的,我也考虑过超时,但这只会减慢我的应用程序 - 不好。
    【解决方案5】:

    @Bernardo Domingues 的回答对我不利,因为我有 500 多种字体的 &lt;select&gt;,由于流量限制,我不想预加载所有字体。

    所以我通过每 500 毫秒重复调用 Canvas.renderAll() 方法解决了这个问题。一次又一次。这样,在我将字体更改为新字体(尚未由浏览器加载)之后 - 首先它将由浏览器下载(我不知道,我不在乎需要多长时间)。一旦加载新字体 - 我的代码将在 500 毫秒内更新整个画布,瞧!我的字体也更新了:)

    【讨论】:

      猜你喜欢
      • 2016-12-11
      • 1970-01-01
      • 1970-01-01
      • 2013-08-31
      • 2021-08-25
      • 2018-05-16
      • 1970-01-01
      • 2013-11-24
      • 2013-02-20
      相关资源
      最近更新 更多