Рисование текста до <canvas>с помощью @ font-face не работает в первый раз - PullRequest
82 голосов
/ 03 мая 2010

Когда я рисую текст на холсте с гарнитурой, загруженной через @ font-face, текст отображается неправильно. Он вообще не отображается (в Chrome 13 и Firefox 5), или неправильный шрифт (Opera 11). Этот тип неожиданного поведения происходит только на первом рисунке с гарнитурой. После этого все работает нормально.

Это стандартное поведение или что-то?

Спасибо.

PS: ниже приведен исходный код контрольного примера

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

Сценарий

 
var x = 30, у = 10; $ ('# draw'). click (function () { var canvas = $ ('canvas') [0], ctx = canvas.getContext ('2d'); ctx.font = '12px "Нажмите Start 2P"'; ctx.fillStyle = '# 000'; ctx.fillText («Привет, мир!», x, y + = 20); ctx.fillRect (x - 20, y - 10, 10, 10); }); $ ( '# Показов CSS') текст ($ ( '# CSS') текст ().). $ ( '# Вид-скрипт') текст ($ ( '# скрипт') текст ().).

Ответы [ 17 ]

62 голосов
/ 03 мая 2010

Рисование на холсте должно произойти и сразу же вернуться при вызове метода fillText. Однако браузер еще не загрузил шрифт из сети, что является фоновой задачей. Поэтому он должен вернуться к шрифту, который имеет в наличии.

Если вы хотите убедиться, что шрифт доступен, на странице предварительно загрузите какой-то другой элемент, например ::10000

<div style="font-family: PressStart;">.</div>
20 голосов
/ 22 ноября 2011

Используйте этот прием и привяжите событие 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 /1734741/javascript-zahvat-sobytiya-zagruzki-po-ssylke
var image = new Image;
image.src = link.href;
image.onerror = function() {
    ctx.font = '50px "Vast Shadow"';
    ctx.textBaseline = 'top';
    ctx.fillText('Hello!', 20, 10);
};
15 голосов
/ 03 сентября 2011

Суть проблемы в том, что вы пытаетесь использовать шрифт, но браузер еще не загрузил его и, возможно, даже не запросил его.Вам нужно что-то, что загрузит шрифт и даст вам обратный вызов после его загрузки;как только вы получите обратный вызов, вы поймете, что можно использовать шрифт.

Посмотрите на Google WebFont Loader ;это похоже на «пользовательский» провайдер и active обратный вызов после загрузки, который заставит его работать.

Я никогда не использовал его раньше, но из быстрого сканирования документов вам нужно сделать cssфайл fonts/pressstart2p.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);
  })();
10 голосов
/ 23 октября 2014

Как насчет использования простого 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>
7 голосов
/ 27 марта 2016

Вы можете загрузить шрифты с помощью 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 .

.

Спецификация API FontFace является рабочим проектом на момент написания этой статьи. См. Таблицу совместимости браузера здесь.

4 голосов
/ 07 февраля 2017

https://drafts.csswg.org/css-font-loading/

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

myFont.load().then(function(font){

  // with canvas, if this is ommited won't work
  document.fonts.add(font);

  console.log('Font loaded');

});
3 голосов
/ 03 мая 2010

Я столкнулся с проблемой, когда играл с ней недавно http://people.opera.com/patrickl/experiments/canvas/scroller/

обошел эту проблему, добавив семейство шрифтов к canvas непосредственно в CSS, поэтому вы можете просто добавить

canvas {font-family: PressStart; }

1 голос
/ 08 марта 2013

Я не уверен, поможет ли это вам, но для решения проблемы с моим кодом я просто создал цикл for в верхней части моего Javascript, который выполнял все шрифты, которые я хотел загрузить. Затем я запустил функцию, чтобы очистить холст и предварительно загрузить нужные элементы на холсте. Пока что это сработало отлично. Это была моя логика, я разместил свой код ниже:

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);
    }
1 голос
/ 06 мая 2013

Я написал 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 для демонстрации.

1 голос
/ 14 июня 2015

Некоторые браузеры поддерживают Загрузка шрифтов CSS . Это позволяет зарегистрировать зарегистрировать обратный вызов, когда все шрифты были загружены. Вы можете отложить рисование холста (или, по крайней мере, рисование текста на холсте) до этого момента и вызвать перерисовку, как только шрифт станет доступен.

...