110

@ font-faceを介してロードされた書体を使用してキャンバスにテキストを描画すると、テキストが正しく表示されません。まったく表示されない(Chrome13およびFirefox5の場合)か、書体が間違っています(Opera 11)。このタイプの予期しない動作は、書体を使用した最初の描画でのみ発生します。その後、すべてが正常に機能します。

それは標準的な動作か何かですか?

ありがとうございました。

PS:以下はテストケースのソースコードです

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>@font-face and &lt;canvas&gt;</title>
        <style id="css">
@font-face {
    font-family: 'Press Start 2P';
    src: url('fonts/PressStart2P.ttf');
}
        </style>
        <style>
canvas, pre {
    border: 1px solid black;
    padding: 0 1em;
}
        </style>
    </head>
    <body>
        <h1>@font-face and &lt;canvas&gt;</h1>
        <p>
            Description: click the button several times, and you will see the problem.
            The first line won't show at all, or with a wrong typeface even if it does.
            <strong>If you have visited this page before, you may have to refresh (or reload) it.</strong>
        </p>
        <p>
            <button id="draw">#draw</button>
        </p>
        <p>
            <canvas width="250" height="250">
                Your browser does not support the CANVAS element.
                Try the latest Firefox, Google Chrome, Safari or Opera.
            </canvas>
        </p>
        <h2>@font-face</h2>
        <pre id="view-css"></pre>
        <h2>Script</h2>
        <pre id="view-script"></pre>
        <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
        <script id="script">
var x = 30,
    y = 10;

$('#draw').click(function () {
    var canvas = $('canvas')[0],
        ctx = canvas.getContext('2d');
    ctx.font = '12px "Press Start 2P"';
    ctx.fillStyle = '#000';
    ctx.fillText('Hello, world!', x, y += 20);
    ctx.fillRect(x - 20, y - 10, 10, 10);
});
        </script>
        <script>
$('#view-css').text($('#css').text());
$('#view-script').text($('#script').text());
        </script>
    </body>
</html>
4

18 に答える 18

80

メソッドを呼び出すと、キャンバス上での描画が発生し、すぐに戻る必要がありますfillText。ただし、ブラウザはまだネットワークからフォントをロードしていません。これはバックグラウンド タスクです。したがって、使用可能なフォントにフォールバックする必要があります。

フォントが利用可能であることを確認したい場合は、ページに他の要素をプリロードしてください。

<div style="font-family: PressStart;">.</div>
于 2010-05-03T07:14:09.463 に答える
26

このトリックを使用して、onerrorイベントをImage要素にバインドします。

デモはこちら: 最新の Chrome で動作します。

var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');

var link = document.createElement('link');
link.rel = 'stylesheet';
link.type = 'text/css';
link.href = 'http://fonts.googleapis.com/css?family=Vast+Shadow';
document.getElementsByTagName('head')[0].appendChild(link);

// Trick from https://stackoverflow.com/questions/2635814/
var image = new Image();
image.src = link.href;
image.onerror = function() {
    ctx.font = '50px "Vast Shadow"';
    ctx.textBaseline = 'top';
    ctx.fillText('Hello!', 20, 10);
};
于 2011-11-22T07:50:17.833 に答える
21

キャンバスで使用する前に、 FontFace APIでフォントを読み込むことができます。

const myFont = new FontFace('My Font', 'url(https://myfont.woff2)');

myFont.load().then((font) => {
  document.fonts.add(font);

  console.log('Font loaded');
});

最初にフォント リソースmyfont.woff2がダウンロードされます。ダウンロードが完了すると、フォントがドキュメントのFontFaceSetに追加されます。

FontFace API の仕様は、この記事の執筆時点では草案です。こちらのブラウザ対応表をご覧ください。

于 2016-03-27T14:09:19.183 に答える
16

問題の核心は、フォントを使用しようとしているが、ブラウザがまだそれをロードしておらず、おそらくそれを要求していないことです. 必要なのは、フォントをロードし、ロードされたときにコールバックを提供するものです。コールバックを取得すると、そのフォントを使用しても問題ないことがわかります。

Google のWebFont Loaderを見てください。「カスタム」プロバイダーのようでactive、ロード後のコールバックが機能するようです。

これまで使用したことはありませんが、ドキュメントを簡単にスキャンすると、次のfonts/pressstart2p.cssように css ファイルを作成する必要があります。

@font-face {
  font-family: 'Press Start 2P';
  font-style: normal;
  font-weight: normal;
  src: local('Press Start 2P'), url('http://lemon-factory.net/reproduce/fonts/Press Start 2P.ttf') format('ttf');
}

次に、次の JS を追加します。

  WebFontConfig = {
    custom: { families: ['Press Start 2P'],
              urls: [ 'http://lemon-factory.net/reproduce/fonts/pressstart2p.css']},
    active: function() {
      /* code to execute once all font families are loaded */
      console.log(" I sure hope my font is loaded now. ");
    }
  };
  (function() {
    var wf = document.createElement('script');
    wf.src = ('https:' == document.location.protocol ? 'https' : 'http') +
        '://ajax.googleapis.com/ajax/libs/webfont/1/webfont.js';
    wf.type = 'text/javascript';
    wf.async = 'true';
    var s = document.getElementsByTagName('script')[0];
    s.parentNode.insertBefore(wf, s);
  })();
于 2011-09-02T22:41:13.283 に答える
14

次のようなフォントを使用して、単純な CSS を使用して div を非表示にするとどうなりますか。

CSS:

#preloadfont {
  font-family: YourFont;
  opacity:0;
  height:0;
  width:0;
  display:inline-block;
}

HTML:

<body>
   <div id="preloadfont">.</div>
   <canvas id="yourcanvas"></canvas>
   ...
</body>
于 2014-10-23T04:21:46.820 に答える
3

最近遊んでいるときに問題にぶつかりましたhttp://people.opera.com/patrickl/experiments/canvas/scroller/

CSS で font-family をキャンバスに直接追加することで回避できたので、追加するだけで済みます。

キャンバス { font-family: PressStart; }

于 2010-05-03T11:55:08.543 に答える
1

ここで提案された修正のほとんどを組み込んだjsfiddleを書きましたが、問題を解決するものはありませんでした。ただし、私は初心者のプログラマーなので、提案された修正を正しくコーディングしていない可能性があります。

http://jsfiddle.net/HatHead/GcxQ9/23/

HTML:

<!-- you need to empty your browser cache and do a hard reload EVERYTIME to test this otherwise it will appear to working when, in fact, it isn't -->

<h1>Title Font</h1>

<p>Paragraph font...</p>
<canvas id="myCanvas" width="740" height="400"></canvas>

CSS:

@import url(http://fonts.googleapis.com/css?family=Architects+Daughter);
 @import url(http://fonts.googleapis.com/css?family=Rock+Salt);
 canvas {
    font-family:'Rock Salt', 'Architects Daughter'
}
.wf-loading p {
    font-family: serif
}
.wf-inactive p {
    font-family: serif
}
.wf-active p {
    font-family:'Architects Daughter', serif;
    font-size: 24px;
    font-weight: bold;
}
.wf-loading h1 {
    font-family: serif;
    font-weight: 400;
    font-size: 42px
}
.wf-inactive h1 {
    font-family: serif;
    font-weight: 400;
    font-size: 42px
}
.wf-active h1 {
    font-family:'Rock Salt', serif;
    font-weight: 400;
    font-size: 42px;
}

JS:

// do the Google Font Loader stuff....
WebFontConfig = {
    google: {
        families: ['Architects Daughter', 'Rock Salt']
    }
};
(function () {
    var wf = document.createElement('script');
    wf.src = ('https:' == document.location.protocol ? 'https' : 'http') +
        '://ajax.googleapis.com/ajax/libs/webfont/1/webfont.js';
    wf.type = 'text/javascript';
    wf.async = 'true';
    var s = document.getElementsByTagName('script')[0];
    s.parentNode.insertBefore(wf, s);
})();

//play with the milliseconds delay to find the threshold - don't forget to empty your browser cache and do a hard reload!
setTimeout(WriteCanvasText, 0);

function WriteCanvasText() {
    // write some text to the canvas
    var canvas = document.getElementById("myCanvas");
    var context = canvas.getContext("2d");
    context.font = "normal" + " " + "normal" + " " + "bold" + " " + "42px" + " " + "Rock Salt";
    context.fillStyle = "#d50";
    context.fillText("Canvas Title", 5, 100);
    context.font = "normal" + " " + "normal" + " " + "bold" + " " + "24px" + " " + "Architects Daughter";
    context.fillText("Here is some text on the canvas...", 5, 180);
}

回避策 最終的にはあきらめて、最初の読み込みでテキストの画像を使用し、同時にテキストをキャンバス表示領域の外にフォント フェイスで配置しました。キャンバス表示領域内のフォントフェイスのその後のすべての表示は問題なく機能しました。これは決してエレガントな回避策ではありません。

ソリューションは私のウェブサイトに組み込まれていますが、誰かが必要な場合は、デモ用に jsfiddle を作成しようとします。

于 2013-05-06T19:42:59.153 に答える
1

これが役立つかどうかはわかりませんが、私のコードの問題を解決するために、ロードしたいすべてのフォントを実行する Javascript の先頭に for ループを作成しました。次に、関数を実行してキャンバスをクリアし、キャンバスに必要なアイテムをプリロードしました。これまでのところ、それは完全に機能しています。それが私のロジックで、コードを以下に投稿しました。

var fontLibrary = ["Acme","Aladin","Amarante","Belgrano","CantoraOne","Capriola","CevicheOne","Chango","ChelaOne","CherryCreamSoda",
"ConcertOne","Condiment","Damion","Devonshire","FugazOne","GermaniaOne","GorditasBold","GorditasRegular",
"KaushanScript","LeckerliOne","Lemon","LilitaOne","LuckiestGuy","Molle","MrDafoe","MrsSheppards",
"Norican","OriginalSurfer","OswaldBold","OswaldLight","OswaldRegular","Pacifico","Paprika","Playball",
"Quando","Ranchers","SansitaOne","SpicyRice","TitanOne","Yellowtail","Yesteryear"];

    for (var i=0; i < fontLibrary.length; i++) {
        context.fillText("Sample",250,50);
        context.font="34px " + fontLibrary[i];
    }

    changefontType();

    function changefontType() {
        selfonttype = $("#selfontype").val();
        inputtextgo1();
    }

    function inputtextgo1() {
        var y = 50;
        var lineHeight = 36;
        area1text = document.getElementById("bag1areatext").value;
        context.clearRect(0, 0, 500, 95)
        context.drawImage(section1backgroundimage, 0, 0);
        context.font="34px " + selfonttype;
        context.fillStyle = seltextcolor;
        context.fillText(area1text, 250, y);
    }
于 2013-03-08T02:06:50.827 に答える
1

一部のブラウザーは、CSS フォントの読み込み仕様をサポートしています。すべてのフォントがロードされたときのコールバックを登録できます。それまでキャンバスの描画 (または少なくともキャンバスへのテキストの描画) を遅らせ、フォントが利用可能になったら再描画をトリガーできます。

于 2015-06-14T10:59:47.593 に答える
0

同じ問題に直面しています。「bobince」などのコメントを読んだ後、次の JavaScript を使用して回避します。

$('body').append("<div id='loadfont' style='font-family: myfont;'>.</div>");
$('#loadfont').remove();
于 2012-07-29T12:17:43.033 に答える
0

まず、他の回答でアドバイスされているように、Google の Web フォント ローダーを使用し、提供されるコールバックに描画コードを追加して、フォントが読み込まれたことを示します。しかし、これで話は終わりではありません。この時点から、ブラウザに大きく依存します。ほとんどの場合は問題なく動作しますが、数百ミリ秒待機するか、ページの別の場所でフォントを使用する必要がある場合があります。私はさまざまなオプションを試しましたが、常に機能する方法の 1 つは、使用するフォント ファミリとフォント サイズの組み合わせを使用して、キャンバスにいくつかのテスト メッセージをすばやく描画することです。背景と同じ色でそれを行うことができるので、それらは目に見えず、非常に速く起こります. その後、フォントは常に私とすべてのブラウザーで機能しました。

于 2011-11-05T01:46:04.523 に答える
0

私の回答は、@font-face ではなく Google Web フォントに対応しています。フォントがキャンバスに表示されないという問題の解決策をどこでも探しました。タイマー、setInterval、font-delay ライブラリ、およびあらゆる種類のトリックを試しました。何も機能しませんでした。(canvas の CSS や canvas 要素の ID に font-family を入れることを含みます。)

ただし、 Google フォントでレンダリングされたテキストのアニメーションは簡単に機能することがわかりました。違いは何ですか?キャンバス アニメーションでは、アニメーション化されたアイテムを何度も再描画します。そこで、テキストを 2 回レンダリングするというアイデアを思いつきました。

それも機能しませんでした-短い(100ミリ秒)タイマー遅延も追加するまで。これまでのところ、Macでのみテストしました。Chrome は 100ms で問題なく動作しました。Safari ではページのリロードが必要だったので、タイマーを 1000 に増やしたところ問題ありませんでした。Firefox 18.0.2 および 20.0 では、Google フォント (アニメーション バージョンを含む) を使用していると、キャンバスに何も読み込まれませんでした。

完全なコード: http://www.macloo.com/examples/canvas/canvas10.html

http://www.macloo.com/examples/canvas/scripts/canvas10.js

于 2013-05-01T16:53:12.887 に答える
0

FontFaceSet.load を使用して問題を解決しようとしています: https://jsfiddle.net/wengshenshun/gr1zkvtq/30

const prepareFontLoad = (fontList) => Promise.all(fontList.map(font => document.fonts.load(font)))

ブラウザーの互換性は、https://developer.mozilla.org/en-US/docs/Web/API/FontFaceSet/loadから確認できます。

于 2018-12-05T16:26:03.900 に答える