HTML5 canvas ctx.fillText satır sonu yapmaz mı?


108

Metin "\ n" içeriyorsa bir tuvale metin ekleyemiyorum. Demek istediğim, satır sonları gösterilmiyor / çalışmıyor.

ctxPaint.fillText("s  ome \n \\n <br/> thing", x, y);

Yukarıdaki kod "s ome \n <br/> thing"tek satırda çizilecektir .

Bu bir fillText sınırlaması mı yoksa yanlış mı yapıyorum? "\ n" ler var ve yazdırılmıyorlar, ancak onlar da çalışmıyor.


1
sona ulaştığınızda otomatik olarak sarmak ister misiniz? veya sadece metinde bulunan satırsonu karakterlerini dikkate almak için?
Gabriele Petrioli

Metni birden çok satıra kaydırın.
Tower

Merhaba twodordan, bu sınırlama hem chrome hem de mozilla'da var mı? İnsanlar genellikle tuvalin üzerine bir konumla koydukları basit html metnini kullanır: örneğin mutlak. Ayrıca ikinci satırlarınız için iki fillText yapabilir ve metninizin Y başlangıç ​​noktasını taşıyabilirsiniz.
Tim

Muhtemel HTML5 Canvas
MvG

TL; DR: Ya fillText()birden çok kez arayın ve ayırmak için yazı tipi yüksekliğinizi kullanın ya da developer.mozilla.org/en-US/docs/Web/API/TextMetrics developer.mozilla.org/en-US/docs/Web/API /… - veya aşağıdaki TextMetrics kullanmayan çok karmaşık "çözümlerden" birini kullanın ...
Andrew

Yanıtlar:


62

Korkarım bu Canvas'ın bir sınırlamasıdır ' fillText. Çoklu hat desteği yoktur. Daha da kötüsü, satır yüksekliğini ölçmenin yerleşik bir yolu yoktur, yalnızca genişliği kendiniz yapmak daha da zor hale getirir!

Pek çok insan kendi çok satırlı desteğini yazdı, belki de sahip olduğu en dikkate değer proje Mozilla Skywriter'dır .

Yapmanız gereken şeyin özü, fillTexther seferinde metnin yüksekliğini y değerine eklerken birden çok çağrıdır. (M'nin genişliğini ölçmek, gökyüzü yazarlarının metni yaklaşık olarak tahmin etmek için yaptıklarına inanıyorum.)


Teşekkür ederim! Bunun can sıkıcı olacağını hissettim ... SKYWRITER hakkında bilmek güzel, ancak fillText () geliştirilinceye kadar sadece "bekleyeceğim". Benim durumumda çok önemli bir anlaşma değildi. Hah, çizgi yüksekliği yok, sanki birisi bunu bilerek yapmış gibi. : D
Spectraljump

19
Dürüst olmak gerekirse, fillText () bunu desteklemek için "iyileştirilirken" nefesini tutmazdım, çünkü bunun nasıl kullanılması gerektiği hissine kapılıyorum (birden fazla çağrı ve yOffset'i kendiniz hesaplamak). Tuval API'sinin gücünün büyük bir kısmının, daha düşük seviyeli çizim işlevselliğini zaten yapabileceklerinizden ayırması olduğunu düşünüyorum (gerekli ölçümleri yapın). Ayrıca, metin boyutunu piksel cinsinden sağlayarak metin yüksekliğini de öğrenebilirsiniz; diğer bir deyişle: context.font = "16px Arial"; - orada yükseklik var; genişlik, dinamik olan tek şeydir.
Lev

1
Bazı ek özellikler için measureText()ben sorunu çözmek düşünüyorum hangi eklenmiştir. Chrome'da bunları etkinleştirmek için bir bayrak var, ancak diğer tarayıcılarda yok ... henüz!
SWdV

@SWdV daha açık olmak gerekirse, bunlar yıllardır spesifikasyondalar, kullanmak için yeterince geniş bir benimsemeye sahip olmamız yıllar alabilir :(
Simon Sarris

67

Metindeki satırsonu karakterleriyle ilgilenmek istiyorsanız, metni satırsonu satırlarına bölerek ve birden çok kez çağırarak simüle edebilirsiniz. fillText()

Böyle bir şey http://jsfiddle.net/BaG4J/1/

var c = document.getElementById('c').getContext('2d');
c.font = '11px Courier';
    console.log(c);
var txt = 'line 1\nline 2\nthird line..';
var x = 30;
var y = 30;
var lineheight = 15;
var lines = txt.split('\n');

for (var i = 0; i<lines.length; i++)
    c.fillText(lines[i], x, y + (i*lineheight) );
canvas{background-color:#ccc;}
<canvas id="c" width="150" height="150"></canvas>


Ben sadece http://jsfiddle.net/BaG4J/2/ adresinde bir kavram kanıtı yaptım ( belirtilen genişlikte mutlak sarma. Henüz işleme kelimeleri kırma yok )
örnek

var c = document.getElementById('c').getContext('2d');
c.font = '11px Courier';

var txt = 'this is a very long text to print';

printAt(c, txt, 10, 20, 15, 90 );


function printAt( context , text, x, y, lineHeight, fitWidth)
{
    fitWidth = fitWidth || 0;
    
    if (fitWidth <= 0)
    {
         context.fillText( text, x, y );
        return;
    }
    
    for (var idx = 1; idx <= text.length; idx++)
    {
        var str = text.substr(0, idx);
        console.log(str, context.measureText(str).width, fitWidth);
        if (context.measureText(str).width > fitWidth)
        {
            context.fillText( text.substr(0, idx-1), x, y );
            printAt(context, text.substr(idx-1), x, y + lineHeight, lineHeight,  fitWidth);
            return;
        }
    }
    context.fillText( text, x, y );
}
canvas{background-color:#ccc;}
<canvas id="c" width="150" height="150"></canvas>


Ve bir kelime sarma ( boşlukları kırma ) kavram kanıtı. http://jsfiddle.net/BaG4J/5/ adresinde
örnek

var c = document.getElementById('c').getContext('2d');
c.font = '11px Courier';

var txt = 'this is a very long text. Some more to print!';

printAtWordWrap(c, txt, 10, 20, 15, 90 );


function printAtWordWrap( context , text, x, y, lineHeight, fitWidth)
{
    fitWidth = fitWidth || 0;
    
    if (fitWidth <= 0)
    {
        context.fillText( text, x, y );
        return;
    }
    var words = text.split(' ');
    var currentLine = 0;
    var idx = 1;
    while (words.length > 0 && idx <= words.length)
    {
        var str = words.slice(0,idx).join(' ');
        var w = context.measureText(str).width;
        if ( w > fitWidth )
        {
            if (idx==1)
            {
                idx=2;
            }
            context.fillText( words.slice(0,idx-1).join(' '), x, y + (lineHeight*currentLine) );
            currentLine++;
            words = words.splice(idx-1);
            idx = 1;
        }
        else
        {idx++;}
    }
    if  (idx > 0)
        context.fillText( words.join(' '), x, y + (lineHeight*currentLine) );
}
canvas{background-color:#ccc;}
<canvas id="c" width="150" height="150"></canvas>


İkinci ve üçüncü örneklerde measureText(), bir dizenin yazdırıldığında ne kadar uzun ( piksel olarak ) olacağını gösteren yöntemi kullanıyorum .


tüm uzun metni nasıl gerekçelendirebilirim?
Amirhossein Tarmast

Uzun, yaslanmış bir metne ihtiyacınız varsa, neden bir tuval kullanasınız?
Mike 'Pomax' Kamermans

39

Belki bu partiye biraz geç geliyorum, ancak metni bir tuvale sarmak için aşağıdaki öğreticiyi mükemmel buldum.

http://www.html5canvastutorials.com/tutorials/html5-canvas-wrap-text-tutorial/

Bundan sonra çoklu hatların çalıştığını düşünebildim (üzgünüm Ramirez, seninki benim için işe yaramadı!). Metni bir tuvale kaydırmak için tam kodum aşağıdaki gibidir:

<script type="text/javascript">

     // http: //www.html5canvastutorials.com/tutorials/html5-canvas-wrap-text-tutorial/
     function wrapText(context, text, x, y, maxWidth, lineHeight) {
        var cars = text.split("\n");

        for (var ii = 0; ii < cars.length; ii++) {

            var line = "";
            var words = cars[ii].split(" ");

            for (var n = 0; n < words.length; n++) {
                var testLine = line + words[n] + " ";
                var metrics = context.measureText(testLine);
                var testWidth = metrics.width;

                if (testWidth > maxWidth) {
                    context.fillText(line, x, y);
                    line = words[n] + " ";
                    y += lineHeight;
                }
                else {
                    line = testLine;
                }
            }

            context.fillText(line, x, y);
            y += lineHeight;
        }
     }

     function DrawText() {

         var canvas = document.getElementById("c");
         var context = canvas.getContext("2d");

         context.clearRect(0, 0, 500, 600);

         var maxWidth = 400;
         var lineHeight = 60;
         var x = 20; // (canvas.width - maxWidth) / 2;
         var y = 58;


         var text = document.getElementById("text").value.toUpperCase();                

         context.fillStyle = "rgba(255, 0, 0, 1)";
         context.fillRect(0, 0, 600, 500);

         context.font = "51px 'LeagueGothicRegular'";
         context.fillStyle = "#333";

         wrapText(context, text, x, y, maxWidth, lineHeight);
     }

     $(document).ready(function () {

         $("#text").keyup(function () {
             DrawText();
         });

     });

    </script>

Tuvalimin ckimliği nerede ve textmetin kutumun kimliği.

Muhtemelen görebileceğiniz gibi standart olmayan bir yazı tipi kullanıyorum. Tuvali değiştirmek için ÖNCEDEN bazı metinlerde fontu kullandığınız sürece @ font-face kullanabilirsiniz - aksi takdirde tuval fontu almaz.

Umarım bu birine yardımcı olur.


26

Metni satırlara bölün ve her birini ayrı ayrı çizin:

function fillTextMultiLine(ctx, text, x, y) {
  var lineHeight = ctx.measureText("M").width * 1.2;
  var lines = text.split("\n");
  for (var i = 0; i < lines.length; ++i) {
    ctx.fillText(lines[i], x, y);
    y += lineHeight;
  }
}

17

İşte benim çözümüm, burada zaten sunulan popüler wrapText () işlevini değiştiriyor. Fonksiyonu tuval bağlamından çağırabilmeniz için JavaScript'in prototip oluşturma özelliğini kullanıyorum.

CanvasRenderingContext2D.prototype.wrapText = function (text, x, y, maxWidth, lineHeight) {

    var lines = text.split("\n");

    for (var i = 0; i < lines.length; i++) {

        var words = lines[i].split(' ');
        var line = '';

        for (var n = 0; n < words.length; n++) {
            var testLine = line + words[n] + ' ';
            var metrics = this.measureText(testLine);
            var testWidth = metrics.width;
            if (testWidth > maxWidth && n > 0) {
                this.fillText(line, x, y);
                line = words[n] + ' ';
                y += lineHeight;
            }
            else {
                line = testLine;
            }
        }

        this.fillText(line, x, y);
        y += lineHeight;
    }
}

Temel kullanım:

var myCanvas = document.getElementById("myCanvas");
var ctx = myCanvas.getContext("2d");
ctx.fillStyle = "black";
ctx.font = "12px sans-serif";
ctx.textBaseline = "top";
ctx.wrapText("Hello\nWorld!",20,20,160,16);

İşte oluşturduğum bir gösteri: http://jsfiddle.net/7RdbL/


Bir cazibe gibi çalıştı. Teşekkür ederim.
couzzi

13

CanvasRenderingContext2D'yi iki işlev ekleyerek genişlettim: mlFillText ve mlStrokeText.

Son sürümü GitHub'da bulabilirsiniz :

Bu işlevlerle bir kutuya miltiline metni doldurabilir / konturlayabilirsiniz. Metni dikey ve yatay olarak hizalayabilirsiniz. (Hesap \ n'ları alır ve ayrıca metni doğrulayabilir).

Prototipler:

işlev mlFillText (metin, x, y, w, h, vAlign, hAlign, satır yüksekliği); işlev mlStrokeText (metin, x, y, w, h, vAlign, hAlign, satır yüksekliği);

VAlign şöyle olabilir: "top", "center" veya "button" Ve hAlign şu olabilir: "left", "center", "right" veya "yasla"

Kitaplığı burada test edebilirsiniz: http://jsfiddle.net/4WRZj/1/

görüntü açıklamasını buraya girin

İşte kütüphanenin kodu:

// Library: mltext.js
// Desciption: Extends the CanvasRenderingContext2D that adds two functions: mlFillText and mlStrokeText.
//
// The prototypes are: 
//
// function mlFillText(text,x,y,w,h,vAlign,hAlign,lineheight);
// function mlStrokeText(text,x,y,w,h,vAlign,hAlign,lineheight);
// 
// Where vAlign can be: "top", "center" or "button"
// And hAlign can be: "left", "center", "right" or "justify"
// Author: Jordi Baylina. (baylina at uniclau.com)
// License: GPL
// Date: 2013-02-21

function mlFunction(text, x, y, w, h, hAlign, vAlign, lineheight, fn) {
    text = text.replace(/[\n]/g, " \n ");
    text = text.replace(/\r/g, "");
    var words = text.split(/[ ]+/);
    var sp = this.measureText(' ').width;
    var lines = [];
    var actualline = 0;
    var actualsize = 0;
    var wo;
    lines[actualline] = {};
    lines[actualline].Words = [];
    i = 0;
    while (i < words.length) {
        var word = words[i];
        if (word == "\n") {
            lines[actualline].EndParagraph = true;
            actualline++;
            actualsize = 0;
            lines[actualline] = {};
            lines[actualline].Words = [];
            i++;
        } else {
            wo = {};
            wo.l = this.measureText(word).width;
            if (actualsize === 0) {
                while (wo.l > w) {
                    word = word.slice(0, word.length - 1);
                    wo.l = this.measureText(word).width;
                }
                if (word === "") return; // I can't fill a single character
                wo.word = word;
                lines[actualline].Words.push(wo);
                actualsize = wo.l;
                if (word != words[i]) {
                    words[i] = words[i].slice(word.length, words[i].length);
                } else {
                    i++;
                }
            } else {
                if (actualsize + sp + wo.l > w) {
                    lines[actualline].EndParagraph = false;
                    actualline++;
                    actualsize = 0;
                    lines[actualline] = {};
                    lines[actualline].Words = [];
                } else {
                    wo.word = word;
                    lines[actualline].Words.push(wo);
                    actualsize += sp + wo.l;
                    i++;
                }
            }
        }
    }
    if (actualsize === 0) lines[actualline].pop();
    lines[actualline].EndParagraph = true;

    var totalH = lineheight * lines.length;
    while (totalH > h) {
        lines.pop();
        totalH = lineheight * lines.length;
    }

    var yy;
    if (vAlign == "bottom") {
        yy = y + h - totalH + lineheight;
    } else if (vAlign == "center") {
        yy = y + h / 2 - totalH / 2 + lineheight;
    } else {
        yy = y + lineheight;
    }

    var oldTextAlign = this.textAlign;
    this.textAlign = "left";

    for (var li in lines) {
        var totallen = 0;
        var xx, usp;
        for (wo in lines[li].Words) totallen += lines[li].Words[wo].l;
        if (hAlign == "center") {
            usp = sp;
            xx = x + w / 2 - (totallen + sp * (lines[li].Words.length - 1)) / 2;
        } else if ((hAlign == "justify") && (!lines[li].EndParagraph)) {
            xx = x;
            usp = (w - totallen) / (lines[li].Words.length - 1);
        } else if (hAlign == "right") {
            xx = x + w - (totallen + sp * (lines[li].Words.length - 1));
            usp = sp;
        } else { // left
            xx = x;
            usp = sp;
        }
        for (wo in lines[li].Words) {
            if (fn == "fillText") {
                this.fillText(lines[li].Words[wo].word, xx, yy);
            } else if (fn == "strokeText") {
                this.strokeText(lines[li].Words[wo].word, xx, yy);
            }
            xx += lines[li].Words[wo].l + usp;
        }
        yy += lineheight;
    }
    this.textAlign = oldTextAlign;
}

(function mlInit() {
    CanvasRenderingContext2D.prototype.mlFunction = mlFunction;

    CanvasRenderingContext2D.prototype.mlFillText = function (text, x, y, w, h, vAlign, hAlign, lineheight) {
        this.mlFunction(text, x, y, w, h, hAlign, vAlign, lineheight, "fillText");
    };

    CanvasRenderingContext2D.prototype.mlStrokeText = function (text, x, y, w, h, vAlign, hAlign, lineheight) {
        this.mlFunction(text, x, y, w, h, hAlign, vAlign, lineheight, "strokeText");
    };
})();

Ve işte kullanım örneği:

var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");

var T = "This is a very long line line with a CR at the end.\n This is the second line.\nAnd this is the last line.";
var lh = 12;

ctx.lineWidth = 1;

ctx.mlFillText(T, 10, 10, 100, 100, 'top', 'left', lh);
ctx.strokeRect(10, 10, 100, 100);

ctx.mlFillText(T, 110, 10, 100, 100, 'top', 'center', lh);
ctx.strokeRect(110, 10, 100, 100);

ctx.mlFillText(T, 210, 10, 100, 100, 'top', 'right', lh);
ctx.strokeRect(210, 10, 100, 100);

ctx.mlFillText(T, 310, 10, 100, 100, 'top', 'justify', lh);
ctx.strokeRect(310, 10, 100, 100);

ctx.mlFillText(T, 10, 110, 100, 100, 'center', 'left', lh);
ctx.strokeRect(10, 110, 100, 100);

ctx.mlFillText(T, 110, 110, 100, 100, 'center', 'center', lh);
ctx.strokeRect(110, 110, 100, 100);

ctx.mlFillText(T, 210, 110, 100, 100, 'center', 'right', lh);
ctx.strokeRect(210, 110, 100, 100);

ctx.mlFillText(T, 310, 110, 100, 100, 'center', 'justify', lh);
ctx.strokeRect(310, 110, 100, 100);

ctx.mlFillText(T, 10, 210, 100, 100, 'bottom', 'left', lh);
ctx.strokeRect(10, 210, 100, 100);

ctx.mlFillText(T, 110, 210, 100, 100, 'bottom', 'center', lh);
ctx.strokeRect(110, 210, 100, 100);

ctx.mlFillText(T, 210, 210, 100, 100, 'bottom', 'right', lh);
ctx.strokeRect(210, 210, 100, 100);

ctx.mlFillText(T, 310, 210, 100, 100, 'bottom', 'justify', lh);
ctx.strokeRect(310, 210, 100, 100);

ctx.mlStrokeText("Yo can also use mlStrokeText!", 0 , 310 , 420, 30, 'center', 'center', lh);

Uncaught ReferenceError: Words is not definedYazı tipini değiştirmeye çalışırsam. Örneğin: ctx.font = '40px Arial';- bunu kemanınıza
eklemeyi

Btw, Words(büyük / küçük harfe duyarlı) değişken nereden geliyor? Hiçbir yerde tanımlanmadı. Kodun bu kısmı yalnızca yazı tipini değiştirdiğinizde çalıştırılır ..
psycho brm

1
@psychobrm Kesinlikle haklısınız. Bu bir hata (ben zaten düzelttim). Kodun bu kısmı yalnızca bir kelimeyi iki satıra bölmeniz gerektiğinde çalıştırılır. Teşekkür ederim!
jbaylina

İhtiyaç duyduğum bazı yükseltmeleri yaptım: boşluk oluşturma, baştaki / sondaki satırsonları oluşturma, kontur oluşturma ve tek bir çağrı ile doldurma (metni iki kez ölçmeyin), for ingenişletilmiş ile iyi çalışmadığı için yinelemeyi de değiştirmek zorunda kaldım Array.prototype. Onu tekrarlayabilmemiz için github'a koyabilir misin?
psikopat brm

@psychobrm Değişikliklerinizi birleştirdim. Teşekkür ederim!
jbaylina

8

JavaScript kullanarak bir çözüm geliştirdim. Güzel değil ama benim için çalıştı:


function drawMultilineText(){

    // set context and formatting   
    var context = document.getElementById("canvas").getContext('2d');
    context.font = fontStyleStr;
    context.textAlign = "center";
    context.textBaseline = "top";
    context.fillStyle = "#000000";

    // prepare textarea value to be drawn as multiline text.
    var textval = document.getElementByID("textarea").value;
    var textvalArr = toMultiLine(textval);
    var linespacing = 25;
    var startX = 0;
    var startY = 0;

    // draw each line on canvas. 
    for(var i = 0; i < textvalArr.length; i++){
        context.fillText(textvalArr[i], x, y);
        y += linespacing;
    }
}

// Creates an array where the <br/> tag splits the values.
function toMultiLine(text){
   var textArr = new Array();
   text = text.replace(/\n\r?/g, '<br/>');
   textArr = text.split("<br/>");
   return textArr;
}

Umarım yardımcı olur!


1
merhaba, metnimin şöyle olduğunu varsayalım var text = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa o zaman tuvalde ne oluyor ???
Amol Navsupe

@Ramirez :) fillText için MaxWidth parametresini koymadı gibi, tuval dışına gidecek
KaHa6uc

6

@ Gaby Petrioli tarafından sağlanan kelime sarma (boşlukları ayırma) kodu çok faydalıdır. Yeni satır karakterlerine destek sağlamak için kodunu genişlettim \n. Ayrıca, çoğu zaman sınırlayıcı kutunun boyutlarına sahip olmak yararlıdır, bu nedenle multiMeasureText()hem genişliği hem de yüksekliği döndürür.

Kodu burada görebilirsiniz: http://jsfiddle.net/jeffchan/WHgaY/76/


bağlantıların süresi doldu, lütfen çalışan bir bağlantınız olsa bile kodu bu yanıta ekleyin. Jsfiddle kapanırsa, bu yanıt olduğu gibi tamamen yararsız hale gelir.
Mike 'Pomax' Kamermans

5

Aşağıda, Colin'in dikey ortalanmış metniwrapText() de destekleyen bir sürümü bulunmaktadır :context.textBaseline = 'middle'

var wrapText = function (context, text, x, y, maxWidth, lineHeight) {
    var paragraphs = text.split("\n");
    var textLines = [];

    // Loop through paragraphs
    for (var p = 0; p < paragraphs.length; p++) {
        var line = "";
        var words = paragraphs[p].split(" ");
        // Loop through words
        for (var w = 0; w < words.length; w++) {
            var testLine = line + words[w] + " ";
            var metrics = context.measureText(testLine);
            var testWidth = metrics.width;
            // Make a line break if line is too long
            if (testWidth > maxWidth) {
                textLines.push(line.trim());
                line = words[w] + " ";
            }
            else {
                line = testLine;
            }
        }
        textLines.push(line.trim());
    }

    // Move text up if centered vertically
    if (context.textBaseline === 'middle')
        y = y - ((textLines.length-1) * lineHeight) / 2;

    // Render text on canvas
    for (var tl = 0; tl < textLines.length; tl++) {
        context.fillText(textLines[tl], x, y);
        y += lineHeight;
    }
};

5

Yalnızca iki satır metne ihtiyacınız varsa, bunları iki farklı fillText çağrısına bölebilir ve her birine farklı bir temel atayabilirsiniz.

ctx.textBaseline="bottom";
ctx.fillText("First line", x-position, y-position);
ctx.textBaseline="top";
ctx.fillText("Second line", x-position, y-position);

4

Bu soru, tuvalin nasıl çalıştığı ile ilgili değil. Bir satır sonu istiyorsanız, sadece bir sonrakinin koordinatlarını ayarlayın ctx.fillText.

ctx.fillText("line1", w,x,y,z)
ctx.fillText("line2", w,x,y,z+20)

3

Hala CSS'ye güvenebileceğinizi düşünüyorum

ctx.measureText().height doesnt exist.

Neyse ki, CSS hack-ardry aracılığıyla (CSS ölçümlerini kullanmanın daha eski uygulamalarını düzeltmenin daha fazla yolu için Tipografik Metriklere bakın), aynı font özellikleriyle a'nın offsetHeight'ını ölçerek metnin yüksekliğini bulabiliriz:

var d = document.createElement(”span”);
d.font = 20px arial
d.textContent = Hello world!”
var emHeight = d.offsetHeight;

from: http://www.html5rocks.com/en/tutorials/canvas/texteffects/


Her ölçmeniz gerektiğinde böyle bir öğe oluşturacak belleğiniz varsa, bu iyi bir çözümdür. Ayrıca şunları da yapabilirsiniz ctx.save(), sonra ctx.font = '12pt Arial' , sonra parseInt( ctx.font, 10 ). Ayarlarken 'pt' kullandığımı unutmayın. Daha sonra PX'e çevrilecek ve yazı tipinin yüksekliği olarak tüketim için bir rakama dönüşebilecektir.
Eric Hodonsky

3

Bu senaryo için burada küçük bir kitaplık oluşturdum: Canvas-Txt

Metni çok satırlı olarak işler ve iyi hizalama modları sunar.

Bunu kullanmak için ya kurmanız ya da bir CDN kullanmanız gerekecek.

Kurulum

npm install canvas-txt --save

JavaScript

import canvasTxt from 'canvas-txt'

var c = document.getElementById('myCanvas')
var ctx = c.getContext('2d')

var txt = 'Lorem ipsum dolor sit amet'

canvasTxt.fontSize = 24

canvasTxt.drawText(ctx, txt, 100, 200, 200, 200)

Bu, aşağıdaki konumlara / boyutlara sahip görünmez bir kutuda metin oluşturacaktır:

{ x: 100, y: 200, height: 200, width: 200 }

Örnek Fiddle

/* https://github.com/geongeorge/Canvas-Txt  */

const canvasTxt = window.canvasTxt.default;
const ctx = document.getElementById('myCanvas').getContext('2d');

const txt = "Lorem ipsum dolor sit amet";
const bounds = { width: 240, height: 80 };

let origin = { x: ctx.canvas.width / 2, y: ctx.canvas.height / 2, };
let offset = { x: origin.x - (bounds.width / 2), y: origin.y - (bounds.height / 2) };

canvasTxt.fontSize = 20;

ctx.fillStyle = '#C1A700';
ctx.fillRect(offset.x, offset.y, bounds.width, bounds.height);

ctx.fillStyle = '#FFFFFF';
canvasTxt.drawText(ctx, txt, offset.x, offset.y, bounds.width, bounds.height);
body {
  background: #111;
}

canvas {
  border: 1px solid #333;
  background: #222; /* Could alternatively be painted on the canvas */
}
<script src="https://unpkg.com/canvas-txt@2.0.6/build/index.js"></script>

<canvas id="myCanvas" width="300" height="160"></canvas>


Devam ettim ve örneği "kendi kendine belgelemeye" yardımcı olacak bazı değişkenler tanımladım. Ayrıca, sınırlayıcı kutunun tuval içinde ortalanmasını da sağlar. Ayrıca arkasına bir dikdörtgen ekledim, böylece ilişkide ortalandığını görebilirsiniz. Harika iş! +1 Fark ettiğim küçük bir şey, saran çizgilerin öndeki boşluklarının bastırılmayacağıdır. Her satırı kırpmak isteyebilirsiniz, örneğin ctx.fillText(txtline.trim(), textanchor, txtY)bunu sadece web sitenizdeki interaktif demonuzda fark ettim.
Bay Polywhirl

@ Bay Polywhirl Cevabı temizlediğiniz için teşekkür ederiz. Döşeme sorununu düzelttim ve 2.0.9sürümü yayınladım . Demo sitesi, paket sürümü güncellenerek düzeltildi. Birden fazla boşlukla ilgili bir sorun var. Düşünceli bir paketle gitmenin mi yoksa sorunu görmezden gelmenin daha mı iyi olduğunu bilmiyorum. Bunun için birçok yerden talepler alıyorum. Devam ettim ve yine de döşeme ekledim. Lorem ipsum dolor, sit <many spaces> amet bunu ilk başta yapmamamın nedeni buydu. Sizce birden çok boşluğu dikkate almalı ve yalnızca bir boşluk varsa kaldırmalıyım?
Geon George

Düzenleme: Görünüşe göre StackOverflow kod bloğu çoklu boşlukları da yok sayıyor
Geon George

2

Bunun da mümkün olduğunu sanmıyorum, ancak bunun için bir çözüm, bir <p>öğe oluşturmak ve onu Javascript ile konumlandırmaktır.


Evet, yapmayı düşündüğüm şey bu. Bu sadece beraber fillText()ve strokeText()CSS neler yapabileceğini ötesinde şeyler yapabilirsiniz.
Tower

Bunu test etmedim, ancak bunun daha iyi bir çözüm olabileceğini düşünüyorum - burada fillText () kullanan diğer çözümler, metnin seçilemeyeceği (veya muhtemelen yapıştırılamayacağı) şekilde bunu yapıyor.
Jerry Asher

2

Aynı sorunu yaşadığım için bununla karşılaştım. Değişken yazı tipi boyutuyla çalışıyorum, bu nedenle bunu hesaba katar:

var texts=($(this).find('.noteContent').html()).split("<br>");
for (var k in texts) {
    ctx.fillText(texts[k], left, (top+((parseInt(ctx.font)+2)*k)));
}

burada .noteContent, kullanıcının düzenlediği içerik düzenlenebilir div'dir (bu, her işlevde bir jQuery içine yerleştirilmiştir) ve ctx.font "14px Arial" (piksel boyutunun önce geldiğine dikkat edin)


0

Canvas öğesi, yeni satır '\ n', sekme '\ t' veya <br /> etiketi gibi karakterleri desteklemez.

Dene:

var newrow = mheight + 30;
ctx.fillStyle = "rgb(0, 0, 0)";
ctx.font = "bold 24px 'Verdana'";
ctx.textAlign = "center";
ctx.fillText("Game Over", mwidth, mheight); //first line
ctx.fillText("play again", mwidth, newrow); //second line 

veya belki birden çok satır:

var textArray = new Array('line2', 'line3', 'line4', 'line5');
var rows = 98;
ctx.fillStyle = "rgb(0, 0, 0)";
ctx.font = "bold 24px 'Verdana'";
ctx.textAlign = "center";
ctx.fillText("Game Over", mwidth, mheight); //first line

for(var i=0; i < textArray.length; ++i) {
rows += 30;
ctx.fillText(textArray[i], mwidth, rows); 
}  

0

Sorun için ES5 çözümüm:

var wrap_text = (ctx, text, x, y, lineHeight, maxWidth, textAlign) => {
  if(!textAlign) textAlign = 'center'
  ctx.textAlign = textAlign
  var words = text.split(' ')
  var lines = []
  var sliceFrom = 0
  for(var i = 0; i < words.length; i++) {
    var chunk = words.slice(sliceFrom, i).join(' ')
    var last = i === words.length - 1
    var bigger = ctx.measureText(chunk).width > maxWidth
    if(bigger) {
      lines.push(words.slice(sliceFrom, i).join(' '))
      sliceFrom = i
    }
    if(last) {
      lines.push(words.slice(sliceFrom, words.length).join(' '))
      sliceFrom = i
    }
  }
  var offsetY = 0
  var offsetX = 0
  if(textAlign === 'center') offsetX = maxWidth / 2
  for(var i = 0; i < lines.length; i++) {
    ctx.fillText(lines[i], x + offsetX, y + offsetY)
    offsetY = offsetY + lineHeight
  }
}

Sorunla ilgili daha fazla bilgiyi blogumda bulabilirsiniz .

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.