126 votes

Dessiner du texte à <canvas> avec @ font-face ne fonctionne pas la première fois

Lorsque je dessine un texte dans un canevas avec une police de caractères chargée via @ font-face, le texte ne s'affiche pas correctement. Cela ne s'affiche pas du tout (dans Chrome 13 et Firefox 5), ou le caractère est incorrect (Opera 11). Ce type de comportement inattendu se produit uniquement lors du premier dessin avec le caractère. Après tout fonctionne bien.

Est-ce le comportement standard ou quelque chose?

Je vous remercie.

PS: Voici le code source du scénario de test.

 <!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>
 

89voto

bobince Points 270740

Dessiner sur la toile doit avoir lieu et revenir immédiatement lorsque vous appelez la méthode fillText . Toutefois, le navigateur n'a pas encore chargé la police à partir du réseau, ce qui constitue une tâche en arrière-plan. Donc, il doit revenir à la police dont il dispose .

Si vous voulez vous assurer que la police est disponible, pré-chargez un autre élément sur la page, par exemple:

 <div style="font-family: PressStart;">.</div>
 

28voto

a paid nerd Points 11716

Utilisez cette astuce et se lier à un onerror événement à un Image élément.

Démo ici : fonctionne sur le dernier 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 http://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);
};
 

17voto

ellisbben Points 3213

Le nœud du problème est que vous essayez d'utiliser la police, mais le navigateur n'a pas chargé de encore et, éventuellement, n'a même pas demandé. Ce que vous avez besoin est quelque chose qui se charge de la police et de vous donner un rappel une fois qu'il est chargé; une fois que vous obtenez le rappel, vous savez qu'il est acceptable d'utiliser la police de caractères.

Regardez Google WebFont Chargeur; il semble comme un "custom" prestataire et un active de rappel après la charge de la faire fonctionner.

Je n'ai jamais utilisé avant, mais à partir d'une analyse rapide de la documentation vous avez besoin de faire un fichier css fonts/pressstart2p.css, comme ceci:

@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');
}

Puis ajouter l'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);
  })();

4voto

Patrick H. Lauke Points 164

J'ai récemment rencontré le problème en jouant avec http://people.opera.com/patrickl/experiments/canvas/scroller/

contourné en ajoutant la famille de polices à la toile directement dans le CSS, de sorte que vous pouvez simplement ajouter

canvas {font-family: PressStart; }

1voto

grapien Points 123

Je ne sais pas si cela vous aidera, mais pour résoudre le problème avec mon code, j'ai simplement créé une boucle for en haut de mon code Javascript, qui parcourait toutes les polices que je voulais charger. J'ai ensuite exécuté une fonction pour effacer le canevas et précharger les éléments que je voulais sur le canevas. Jusqu'à présent, cela a parfaitement fonctionné. C'était ma logique, j'ai posté mon code ci-dessous:

 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);
    }
 

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X