टेक्स्ट को <font> फेस-फॉन्ट के साथ पहली बार में दिखाने से काम नहीं चलता है


93

जब मैं कैनवास में एक टेक्स्ट टाइप करता हूं जिसमें एक टाइपफेस होता है जो @ फॉन्ट-फेस के जरिए लोड होता है, टेक्स्ट सही से नहीं दिखता है। यह बिल्कुल नहीं दिखाता (क्रोम 13 और फ़ायरफ़ॉक्स 5 में), या टाइपफेस गलत है (ओपेरा 11)। इस प्रकार का अप्रत्याशित व्यवहार केवल टाइपफेस के साथ पहली ड्राइंग में होता है। इसके बाद सबकुछ ठीक हो जाता है।

यह मानक व्यवहार है या कुछ और?

धन्यवाद।

पुनश्च: निम्नलिखित परीक्षण मामले का स्रोत कोड है

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

1
ब्राउजर फ़ॉन्ट को पृष्ठभूमि में, अतुल्यकालिक रूप से लोड करता है। यह सामान्य व्यवहार है। Paulirish.com/2009/fighting-the-font-face-fout
थॉमस

जवाबों:


71

कैनवास पर आरेखण करना होता है और जब आप fillTextविधि कहते हैं तो तुरंत वापस आ जाते हैं । हालांकि, ब्राउज़र ने अभी तक नेटवर्क से फ़ॉन्ट लोड नहीं किया है, जो एक पृष्ठभूमि कार्य है। इसलिए इसे वापस उस फ़ॉन्ट पर गिरना पड़ता है जो इसके पास उपलब्ध है।

यदि आप यह सुनिश्चित करना चाहते हैं कि फ़ॉन्ट उपलब्ध है, तो पृष्ठ पर कुछ अन्य तत्व रखें, जैसे:

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

3
आपको जोड़ने के लिए लुभाया जा सकता है display: none, लेकिन इससे ब्राउज़र को फ़ॉन्ट लोड करना छोड़ना पड़ सकता है। एक के बजाय एक जगह का उपयोग करना बेहतर है .
थॉमस

6
स्पेस का उपयोग करने से IE को व्हाट्सएप नोड को दूर फेंकने का कारण होगा जो कि फॉन्ट में रेंडर करने के लिए कोई टेक्स्ट नहीं छोड़ता है। बेशक IE अभी तक कैनवास का समर्थन नहीं करता है, इसलिए यह अज्ञात है कि क्या भविष्य-IE ऐसा करना जारी रखेगा, और क्या इससे फ़ॉन्ट लोडिंग व्यवहार पर प्रभाव पड़ेगा, लेकिन यह एक लंबे समय से स्थायी IE HTML- पार्सिंग समस्या है।
bobince

1
क्या फ़ॉन्ट को प्रीलोड करने का कोई आसान तरीका नहीं है? उदाहरण के लिए इसे किसी तरह से जावास्क्रिप्ट के माध्यम से मजबूर करें?
जोशुआ

@ जोशुआ: केवल पृष्ठ पर एक तत्व बनाकर और उस पर फ़ॉन्ट सेट करके, यानी। उपरोक्त के रूप में एक ही सामग्री बनाने लेकिन गतिशील रूप से।
बॉबसन

17
यह जोड़ने की गारंटी नहीं है कि जावास्क्रिप्ट निष्पादित होने पर फ़ॉन्ट पहले से लोड हो जाएगा। मुझे देरी से (सेटटाइमआउट) प्रश्न में फ़ॉन्ट का उपयोग करके अपनी स्क्रिप्ट निष्पादित करनी थी, जो निश्चित रूप से खराब है।
निक

23

इस ट्रिक का उपयोग करें और किसी onerrorईवेंट को एक Imageतत्व से बांधें ।

यहां डेमो : नवीनतम क्रोम पर काम करता है।

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

3
स्मार्ट चाल। ध्यान दें कि आप सीएसएस लोड कर रहे हैं, जो बदले में, वास्तविक फ़ॉन्ट फ़ाइल (उदाहरण के लिए, .ttf, .woff, आदि) का संदर्भ रखता है। मुझे आपकी चाल का उपयोग दो बार करना पड़ा, एक बार सीएसएस फ़ाइल के लिए, और एक बार संदर्भित फ़ॉन्ट फ़ाइल (.woff) के लिए यह सुनिश्चित करने के लिए कि सब कुछ लोड हो गया था।
मैग्मा

1
.Ttf फ़ॉन्ट के साथ इस दृष्टिकोण की कोशिश की - क्रोम (41.0.2272.101 मीटर) पर दृढ़ता से काम नहीं करता है। यहां तक ​​कि 5 सेकंड में सेटटाइमआउट मदद नहीं करता है - पहले रेंडर डिफ़ॉल्ट फ़ॉन्ट के साथ जाता है।
मिखाइल फ़ेडोसेनका

2
इससे पहले कि आप src
asdjfiasd

1
यह भी "नई छवि?" लापता कोष्ठक है।
asdjfiasd

@asdjfiasd Parens की आवश्यकता नहीं है और, भले ही srcविशेषता सेट हो, लोडिंग अगले निष्पादन ब्लॉक में शुरू हो जाएगा।
एक सशुल्क nerd

16

समस्या यह है कि आप फ़ॉन्ट का उपयोग करने का प्रयास कर रहे हैं, लेकिन ब्राउज़र ने इसे अभी तक लोड नहीं किया है और संभवतः इसका अनुरोध भी नहीं किया है। आपको ऐसी चीज़ की ज़रूरत है जो फ़ॉन्ट को लोड करने और लोड होने के बाद आपको कॉलबैक दे; एक बार जब आप कॉलबैक प्राप्त करते हैं, तो आप जानते हैं कि फ़ॉन्ट का उपयोग करना ठीक है।

Google के WebFont लोडर को देखें ; ऐसा लगता है कि "कस्टम" प्रदाता और activeलोड के बाद कॉलबैक यह काम करेगा।

मैंने पहले कभी इसका उपयोग नहीं किया है, लेकिन डॉक्स के त्वरित स्कैन से आपको एक सीएसएस फ़ाइल बनाने की आवश्यकता है 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');
}

फिर निम्नलिखित जेएस जोड़ें:

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

13

कैनवास में उपयोग करने से पहले आप फोंटफेस एपीआई के साथ फोंट लोड कर सकते हैं :

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 का विनिर्देश इस लेखन के समय एक कार्यशील मसौदा है। ब्राउज़र संगतता तालिका यहां देखें।


1
आप गायब हैं document.fonts.add। ब्रूनो का जवाब देखें
पचेरियर

धन्यवाद @ स्पेसियर! मेरे उत्तर को अपडेट किया।
फ्रेड बर्गमैन 21

यह तकनीक प्रयोगात्मक है और अधिकांश ब्राउज़रों द्वारा समर्थित नहीं है।
माइकल ज़ेलेंस्की

11

इस तरह से फ़ॉन्ट का उपयोग करके एक डिव को छिपाने के लिए सरल सीएसएस का उपयोग करने के बारे में क्या:

सीएसएस:

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

HTML:

<body>
   <div id="preloadfont">.</div>
   <canvas id="yourcanvas"></canvas>
   ...
</body>


3

मैं जब हाल ही में इसके साथ खेल रहा मुद्दा टकरा गए http://people.opera.com/patrickl/experiments/canvas/scroller/

सीधे सीएसएस में फ़ॉन्ट-परिवार को कैनवास में जोड़कर इसके चारों ओर काम किया, ताकि आप बस जोड़ सकें

कैनवास {फ़ॉन्ट-परिवार: प्रेसस्टार्ट; }


3
काम करने के लिए प्रतीत नहीं होता है: क्रोम 12 में परीक्षण किया गया है : फ़ॉन्ट को याद करने के लिए इसे कुछ समय ताज़ा करें
रयान बडौर

1

मुझे यकीन नहीं है कि यह आपकी मदद करेगा, लेकिन मेरे कोड के साथ समस्या को हल करने के लिए मैंने बस अपनी जावास्क्रिप्ट के शीर्ष पर एक लूप के लिए बनाया जो सभी फोंट के माध्यम से चला था जिसे मैं लोड करना चाहता था। फिर मैंने कैनवास को साफ़ करने के लिए एक फ़ंक्शन चलाया और कैनवास पर मेरे द्वारा वांछित आइटम को लोड करना था। अब तक इसने पूरी तरह से काम किया है। यह मेरा तर्क था मैंने अपना कोड नीचे पोस्ट किया है:

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

मैंने एक 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>

सीएसएस:

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

जे एस:

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

कुछ ब्राउज़र सीएसएस फ़ॉन्ट लोडिंग विनिर्देशन का समर्थन करते हैं । यह आपको सभी फोंट लोड होने पर कॉलबैक रजिस्टर करने की अनुमति देता है। आप तब तक अपने कैनवास (या अपने कैनवास में कम से कम ड्राइंग पाठ) को चित्रित करने में देरी कर सकते हैं, और फ़ॉन्ट उपलब्ध होने के बाद एक redraw को ट्रिगर कर सकते हैं।


0

सबसे पहले Google के वेब फ़ॉन्ट लोडर का उपयोग करें जैसा कि अन्य उत्तर में सलाह दी गई थी और फोंट लोड किए गए हैं यह इंगित करने के लिए आपके आह्वान कोड को कॉलबैक में जोड़ें। हालाँकि यह कहानी का अंत नहीं है। इस बिंदु से यह बहुत ब्राउज़र पर निर्भर है। अधिकांश समय यह ठीक काम करेगा, लेकिन कभी-कभी कुछ सैकड़ों मिलीसेकंड के लिए प्रतीक्षा करने या पेज पर कहीं और फोंट का उपयोग करने की आवश्यकता हो सकती है। मैंने विभिन्न विकल्पों की कोशिश की और एक विधि जो हमेशा काम करती है वह है फॉन्ट परिवार और फॉन्ट साइज़ कॉम्बिनेशन के साथ कैनवास में कुछ परीक्षण संदेशों को जल्दी से आकर्षित करना जो आप उपयोग करने जा रहे हैं। आप इसे पृष्ठभूमि के समान रंग के साथ कर सकते हैं, इसलिए वे दिखाई भी नहीं देंगे और यह बहुत तेज़ी से होगा। उसके बाद फोंट ने हमेशा मेरे लिए और सभी ब्राउज़रों में काम किया।


0

मेरा उत्तर @ फॉन्ट-फेस के बजाय Google वेब फोंट को संबोधित करता है। मैंने कैनवस में दिखाई जाने वाली फ़ॉन्ट की समस्या के समाधान के लिए हर जगह खोज की। मैंने टाइमर्स, सेटइंटरवल, फॉन्ट-डिले लाइब्रेरी, और सभी प्रकार के ट्रिक्स की कोशिश की। कुछ भी काम नहीं किया। (कैनवास के लिए CSS या कैनवास तत्व की आईडी में फ़ॉन्ट-परिवार को शामिल करना।)

हालाँकि, मैंने पाया कि Google फ़ॉन्ट में दिए गए एनिमेटिंग टेक्स्ट ने आसानी से काम किया। क्या फर्क पड़ता है? कैनवास एनीमेशन में, हम एनिमेटेड आइटम को बार-बार फिर से आकर्षित करते हैं। इसलिए मुझे पाठ को दो बार प्रस्तुत करने का विचार आया।

यह भी काम नहीं किया - जब तक कि मैंने एक छोटा (100ms) टाइमर विलंब भी नहीं जोड़ा। मैंने केवल एक मैक पर परीक्षण किया है। क्रोम ने 100ms में ठीक काम किया। सफारी को एक पृष्ठ पुनः लोड करने की आवश्यकता थी, इसलिए मैंने टाइमर को 1000 तक बढ़ा दिया, और फिर यह ठीक था। अगर मैं Google फोंट (एनीमेशन संस्करण सहित) का उपयोग कर रहा था तो फ़ायरफ़ॉक्स 18.0.2 और 20.0 कैनवास पर कुछ भी लोड नहीं करेगा।

पूरा कोड: http://www.macloo.com/examples/canvas/canvas10.html

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


0

एक ही समस्या का सामना करता है। "बॉबीसन" और अन्य टिप्पणियों को पढ़ने के बाद, मैं इसका उपयोग करने के लिए निम्नलिखित जावास्क्रिप्ट का उपयोग करता हूं:

$('body').append("<div id='loadfont' style='font-family: myfont;'>.</div>");
$('#loadfont').remove();

0

यदि आप हर बार नया फ़ॉन्ट लोड करना चाहते हैं (और संभवतः रेंडरिंग को बदलते हैं) तो फॉन्ट लोडिंग एपी के लिए एक अच्छी घटना है। मुझे पूर्ण गतिशील वातावरण में वादे के साथ समस्या थी।

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
}

0

कैनवस डोम लोडिंग से स्वतंत्र रूप से तैयार किया गया है। प्रीलोड तकनीक तभी काम करेगी जब प्रीलोड के बाद कैनवास खींचा जाएगा।

मेरा समाधान, भले ही यह सबसे अच्छा न हो:

सीएसएस:

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

जावास्क्रिप्ट:

function init() {
    myCanvas.draw();
}

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 से पा सकते हैं


0

इस लेख ने आलसी लोडेड फोंट के साथ मेरे मुद्दों को छाँटा नहीं है।

प्रदर्शन के मुद्दों से बचने और पेज लोडिंग में तेजी लाने के लिए वेब फोंट कैसे लोड करें

इससे मुझे मदद मिली ...

    <link rel="preload" as="font" href="assets/fonts/Maki2/fontmaki2.css" rel="stylesheet" crossorigin="anonymous">

-4

नीचे के रूप में एक देरी जोड़ें

<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>
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.