텍스트 그리기
@ font-face를 통해로드 된 서체로 캔버스에 텍스트를 그릴 때 텍스트가 올바르게 표시되지 않습니다. 전혀 표시되지 않거나 (Chrome 13 및 Firefox 5에서) 서체가 잘못되었습니다 (Opera 11). 이러한 유형의 예기치 않은 동작은 서체가있는 첫 번째 드로잉에서만 발생합니다. 그 후 모든 것이 잘 작동합니다.
표준 행동입니까?
감사합니다.
추신 : 다음은 테스트 케이스의 소스 코드입니다.
<!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>
이 트릭을 사용 하고 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);
};
문제의 핵심은 글꼴을 사용하려고하지만 브라우저가 글꼴을 아직로드하지 않았고 요청하지 않았을 수도 있다는 것입니다. 필요한 것은 글꼴을로드하고로드 된 후 콜백을 제공하는 것입니다. 콜백을 받으면 글꼴을 사용해도된다는 것을 알 수 있습니다.
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);
})();
간단한 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>
캔버스에서 사용하기 전에 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의 사양은이 글을 쓰는 시점의 작업 초안입니다. 여기에서 브라우저 호환성 표를 참조하십시오.
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에서 직접 캔버스에 font-family를 추가하여 문제를 해결했습니다.
canvas {font-family : PressStart; }
이것이 도움이 될지는 모르겠지만 내 코드의 문제를 해결하기 위해로드하려는 모든 글꼴을 실행하는 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);
}
여기에 제안 된 수정 사항의 대부분을 통합하는 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);
}
Workaround I eventually gave in and, on the first load, used an image of the text while also positioning the text with the font-faces outside of the canvas display area. All subsequent displays of the font-faces within the canvas display area worked no problem. This is not an elegant workaround by any means.
The solution is baked into my website but if anyone needs I will try to create a jsfiddle to demonstrate.
Some browsers support the CSS Font Loading specification. It allows you to register register a callback for when all the fonts have been loaded. You can delay drawing your canvas (or at least drawing text into your canvas) until then, and trigger a redraw once the font is available.
First of all use Google's Web Font loader as was advised in the other answer and add your drawing code to the callback it provides to indicate the fonts have been loaded. However this is not the end of the story. From this point it is very browser dependent. Most of the time it will work fine, but sometimes it may be required to wait for couple hundreds of milliseconds or use the fonts somewhere else on the page. I tried different options and the one method that afaik always works is to quickly draw some test messages in the canvas with the font family and font size combinations that you are going to use. You can do it with the same color as background, so they won't even be visible and it will happen very fast. After that fonts always worked for me and in all browsers.
My answer addresses Google Web fonts rather than @font-face. I searched everywhere for a solution to the problem of the font not showing up in the canvas. I tried timers, setInterval, font-delay libraries, and all kinds of tricks. Nothing worked. (Including putting font-family in the CSS for canvas or the ID of the canvas element.)
However, I found that animating text rendered in a Google font worked easily. What's the difference? In canvas animation, we re-draw the animated items again and again. So I got the idea to render the text twice.
That did not work either -- until I also added a short (100ms) timer delay. I've only tested on a Mac so far. Chrome worked fine at 100ms. Safari required a page reload, so I increased the timer to 1000, and then it was fine. Firefox 18.0.2 and 20.0 wouldn't load anything on the canvas if I was using Google fonts (including the animation version).
Full code: http://www.macloo.com/examples/canvas/canvas10.html
http://www.macloo.com/examples/canvas/scripts/canvas10.js
Faces same problem. After reading "bobince" and others comments, I uses following javascript to workaround it :
$('body').append("<div id='loadfont' style='font-family: myfont;'>.</div>");
$('#loadfont').remove();
If you want to redraw everytime a new font is loaded (and probably change the rendering) the font loading api has a nice event for that, too. I had problems with the Promise in a complete dynamic environment.
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
}
The canvas is drawn independently of the DOM loading. The preload technique will only work if the canvas is drawn after the preload.
My solution, even if it is not the best:
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();
}
I try to use FontFaceSet.load to fix the problem: https://jsfiddle.net/wengshenshun/gr1zkvtq/30
const prepareFontLoad = (fontList) => Promise.all(fontList.map(font => document.fonts.load(font)))
You can find the browser compatibility from https://developer.mozilla.org/en-US/docs/Web/API/FontFaceSet/load
Add a delay as below
<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>
'code' 카테고리의 다른 글
Docker, 그것은 무엇이며 목적은 무엇입니까 (0) | 2020.09.22 |
---|---|
ASP.NET 웹 사이트를 ASP.NET 웹 응용 프로그램으로 변환하는 방법 (0) | 2020.09.22 |
URL의 조각 식별자에 유효한 문자 목록? (0) | 2020.09.22 |
Mailbox unavailable. The server response was: 5.7.1 Unable to relay for abc@xyz.com [closed] (0) | 2020.09.21 |
How to get status code from webclient? (0) | 2020.09.21 |