Когда я рисую текст на холсте шрифтом, который загружается через @ font-face, текст отображается неправильно. Он вообще не отображается (в Chrome 13 и Firefox 5), или шрифт неправильный (Opera 11). Такое неожиданное поведение возникает только при первом рисовании шрифтом. После этого все работает нормально.
Это стандартное поведение или что-то в этом роде?
Спасибо.
PS: Ниже приведен исходный код тестового примера.
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>@font-face and <canvas></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 <canvas></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>
Ответы:
Рисование на холсте должно происходить и возвращаться сразу после вызова
fillText
метода. Однако браузер еще не загрузил шрифт из сети, что является фоновой задачей. Поэтому он должен вернуться к шрифту, который у него есть.Если вы хотите убедиться, что шрифт доступен, предварительно загрузите какой-либо другой элемент на странице, например:
<div style="font-family: PressStart;">.</div>
источник
display: none
, но из-за этого браузеры могут пропустить загрузку шрифта. Лучше использовать пробел вместо.
.Используйте этот трюк и привяжите
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 /programming/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); };
источник
src
атрибут установлен, загрузка начнется в следующем блоке выполнения.Суть проблемы в том, что вы пытаетесь использовать шрифт, но браузер еще не загрузил его и, возможно, даже не запросил его. Вам нужно что-то, что загрузит шрифт и предоставит вам обратный вызов после его загрузки; как только вы получите обратный вызов, вы поймете, что использовать шрифт можно.
Посмотрите на 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); })();
источник
Вы можете загружать шрифты с помощью 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 является рабочим проектом на момент написания этой статьи. См. Таблицу совместимости браузеров здесь.
источник
document.fonts.add
. См. Ответ Бруно.Как насчет использования простого 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>
источник
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'); });
источник
я недавно столкнулся с проблемой, играя с ней http://people.opera.com/patrickl/experiments/canvas/scroller/
обошли это, добавив семейство шрифтов на холст прямо в CSS, так что вы можете просто добавить
холст {семейство шрифтов: PressStart; }
источник
Я не уверен, поможет ли это вам, но чтобы решить проблему с моим кодом, я просто создал цикл 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); }
источник
Я написал 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 для демонстрации.
источник
Некоторые браузеры поддерживают на Загрузка CSS Font спецификации. Это позволяет вам зарегистрировать обратный вызов, когда все шрифты будут загружены. Вы можете отложить рисование холста (или, по крайней мере, рисование текста на холсте) до этого момента и запустить перерисовку, как только шрифт станет доступен.
источник
В этой статье я разобрался с моими проблемами с не отображаемыми лениво загруженными шрифтами.
Как загружать веб-шрифты, чтобы избежать проблем с производительностью и ускорить загрузку страницы
Это помогло мне ...
<link rel="preload" as="font" href="assets/fonts/Maki2/fontmaki2.css" rel="stylesheet" crossorigin="anonymous">
источник
Прежде всего используйте загрузчик веб-шрифтов Google, как было рекомендовано в другом ответе, и добавьте свой код рисования в обратный вызов, который он предоставляет, чтобы указать, что шрифты загружены. Однако это не конец истории. С этого момента он очень зависит от браузера. В большинстве случаев он будет работать нормально, но иногда может потребоваться подождать пару сотен миллисекунд или использовать шрифты в другом месте на странице. Я пробовал разные варианты, и один метод, который всегда работает afaik, - это быстро нарисовать несколько тестовых сообщений на холсте с комбинациями семейства и размера шрифта, которые вы собираетесь использовать. Вы можете сделать это тем же цветом, что и фон, чтобы они даже не были видны, и это произойдет очень быстро. После этого у меня всегда работали шрифты во всех браузерах.
источник
Мой ответ касается веб-шрифтов Google, а не @ font-face. Я повсюду искал решение проблемы с отсутствием шрифта на холсте. Я пробовал таймеры, setInterval, библиотеки задержки шрифтов и всевозможные трюки. Ничего не получилось. (Включая размещение font-family в CSS для холста или идентификатора элемента холста.)
Однако я обнаружил, что анимация текста, отображаемого шрифтом Google, работает легко. Какая разница? В анимации холста мы снова и снова перерисовываем анимированные элементы. Так что мне пришла в голову идея визуализировать текст дважды.
Это тоже не сработало - пока я не добавил короткую (100 мс) задержку таймера. Пока тестировал только на Mac. Хром нормально работал на 100 мс. 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
источник
Столкнулся с той же проблемой. Прочитав «bobince» и другие комментарии, я использую следующий javascript, чтобы обойти это:
$('body').append("<div id='loadfont' style='font-family: myfont;'>.</div>"); $('#loadfont').remove();
источник
Если вы хотите перерисовывать каждый раз при загрузке нового шрифта (и, возможно, изменять рендеринг), у api загрузки шрифта есть хорошее событие для этого. У меня были проблемы с Promise в полностью динамической среде.
var fontFaceSet = document.fonts; if (fontFaceSet && fontFaceSet.addEventListener) { fontFaceSet.addEventListener('loadingdone', function () { // Redraw something }); } else { // no fallback is possible without this API as a font files download can be triggered // at any time when a new glyph is rendered on screen }
источник
Холст отрисовывается независимо от загрузки DOM. Техника предварительной загрузки будет работать только в том случае, если холст будет нарисован после предварительной загрузки.
Мое решение, даже если оно не самое лучшее:
CSS:
.preloadFont { font-family: 'Audiowide', Impact, Charcoal, sans-serif, cursive; font-size: 0; position: absolute; visibility: hidden; }
HTML:
<body onload="init()"> <div class="preloadFont">.</div> <canvas id="yourCanvas"></canvas> </body>
JavaScript:
function init() { myCanvas.draw(); }
источник
Я пытаюсь использовать 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.
источник
Добавьте задержку, как показано ниже
<script> var c = document.getElementById('myCanvas'); var ctx = c.getContext('2d'); setTimeout(function() { ctx.font = "24px 'Proxy6'"; // uninstalled @fontface font style ctx.textBaseline = 'top'; ctx.fillText('What!', 20, 10); }, 100); </script>
источник