2013-03-26 20 views
5

Das Problem, das ich habe, ist, den von einem Benutzer eingegebenen Text vertikal zentriert innerhalb des Canvas-Elements zu halten. Ich habe eine Testumgebung aufgebaut, um dieses Problem zu lösen, das ich in diesem Beitrag zusammen mit einer Geige vorgestellt habe. Hier ist mein Code:Text vertikal zentriert auf Canvas halten

HTML:

Enter Your Text: <br/> 
<textarea id="inputtextuser" onkeyup="inputtextgo()" name="Text">Enter Your</textarea> <br/> 
TextBaseline: 
<select id="inputtextbaseline" onchange="inputtextgo()";> 
    <option value="alphabetic">alphabetic</option> 
    <option value="top">top</option> 
    <option value="bottom">bottom</option> 
    <option value="middle">middle</option> 
    <option value="hanging">hanging</option> 
</select> <br/> 
<canvas id="canvas1" width="300px" height="200px" >Your browser does not support the HTML5 canvas tag.</canvas> <br/> 
<div id ="textheightentered"></div> 

CSS:

canvas { 
    border: solid 1px black; 
} 

JavaScript/jQuery:

//Declaring the Canvas 
var canvas1 = document.getElementById('canvas1'); 
context1 = canvas1.getContext('2d'); 

//running the function to update the canvas 
inputtextgo(); 

function inputtextgo() { 
    //Retrieving the text entered by the user 
    var inputtext = document.getElementById("inputtextuser").value; 
    //Calling the function to calculate the height on the text entered by the user 
    var textheight = fontheight(inputtext); 
    //retrieving the baseline selected by the user 
    var baseline = document.getElementById("inputtextbaseline").value; 
    //calculating the new y needed to center the text based on the height of the text 
    var y = 100 + textheight/2; 

    //Updating the canvas for the new text entered by the user 
    context1.clearRect(0, 0, 300, 200); 
    context1.font = "36px arial"; 
    context1.textBaseline = baseline; 
    context1.fillText (inputtext, 0, y); 

    //Drawing a line across the middle of the canvas for reference 
    context1.strokeStyle="red"; 
    context1.moveTo(5,100); 
    context1.lineTo(290,100); 
    context1.stroke(); 
    $("#textheightentered").text("Text Height: " + textheight); 
} 

function fontheight(text){ 

    var canvas=document.createElement("canvas"); 
    canvas.width = 1000; 
    canvas.height = 200; 
    var ctx=canvas.getContext("2d"); 

    function measureTextHeight(left, top, width, height,text) { 

     // Draw the text in the specified area 
     ctx.save(); 
     ctx.clearRect(0,0, canvas.width, canvas.height); 
     ctx.baseline = "top"; 
     ctx.fillText(text, 0, 35); // This seems like tall text... Doesn't it? 
     ctx.restore(); 

     // Get the pixel data from the canvas 
     var data = ctx.getImageData(left, top, width, height).data, 
      first = false, 
      last = false, 
      r = height, 
      c = 0; 

     // Find the last line with a non-white pixel 
     while(!last && r) { 
      r--; 
      for(c = 0; c < width; c++) { 
       if(data[r * width * 4 + c * 4 + 3]) { 
        last = r; 
        break; 
       } 
      } 
     } 

     // Find the first line with a non-white pixel 
     while(r) { 
      r--; 
      for(c = 0; c < width; c++) { 
       if(data[r * width * 4 + c * 4 + 3]) { 
        first = r; 
        break; 
       } 
      } 

      // If we've got it then return the height 
      if(first != r) return last - first; 
     } 

     // We screwed something up... What do you expect from free code? 
     return 0; 
    } 
    ctx.font= "36px arial"; 
    var height = measureTextHeight(0, 0, canvas.width, canvas.height,text); 
    //return the height of the string 
    return height; 
} // end $(function(){}); 

JSFiddle: http://jsfiddle.net/grapien/R6DWN/3/

Die Frage, die ich habe ist Wenn der Benutzer beispielsweise einen Kleinbuchstaben "y" eingibt, ändert sich die Texthöhe und der Text bleibt nicht in der Mitte der Zeichenfläche. Dies aufgrund der Tatsache, dass die in der y-Variable durchgeführte Grundlinienkorrektur in Abhängigkeit von dem eingegebenen Text (Kombination von Klein- und Großbuchstaben) unterschiedlich sein muss, da der Text unter der Grundlinie die in der y-Variable durchgeführte Korrektur verfälscht.

Dies ist, wo ich meine Probleme habe, wie ich den Text jederzeit innerhalb des Canvas-Elements zentriert halten möchte. Das einzige, was mir einfällt, ist die Berechnung der nicht leeren Pixel über einem Punkt unterhalb des Referenzpunkts der Textbasislinie. Verwenden Sie dann den Unterschied zwischen der Grundlinie und den Textenden, um den Text auf der Leinwand zu zentrieren. Ich bin mir nicht sicher, wie Sie dieses Skript schreiben oder ob es überhaupt möglich ist. Aber das ist der beste Ansatz, den ich mir ausgedacht habe.

Wenn jemand irgendwelche Gedanken oder Anleitungen hat, würde es sehr geschätzt werden, da die Entwicklung eines Ansatzes, um dieses Problem zu lösen, mich ratlos gemacht hat.

+0

Vielen Dank für die Bearbeitung meiner Post Matt, es sieht aus wie ein Ich habe ein paar Dinge in meiner Kritik verpasst. – grapien

Antwort

0

Ich glaube, ich habe diese Frage mit der Technik gelöst, die ich in der Frage angegeben habe. Ich habe eine neue Funktion erstellt, die den Schriftgrad berechnet, der unter der Grundlinie des eingegebenen Textes liegt. Verwenden einer ähnlichen Technik wie bei der Berechnung der Höhe. Ich verwende die alphabetische Grundlinie und berechne dann die Pixel, die Inhalt über dieser Grundlinie enthalten. Siehe die folgende Funktion.

function fontheight2(text){ 

    var canvas=document.createElement("canvas"); 
    canvas.width = 1000; 
    canvas.height = 200; 
    var ctx=canvas.getContext("2d"); 

    function measureTextHeight(left, top, width, height,text) { 

     // Draw the text in the specified area 
     ctx.save(); 
     ctx.clearRect(0,0, canvas.width, canvas.height); 
     ctx.fillText(text, 0, 100); // This seems like tall text... Doesn't it? 
     ctx.restore(); 

     // Get the pixel data from the canvas 
     var data = ctx.getImageData(left, top, width, height).data, 
      first = false, 
      last = false, 
      r = 100, 
      c = 0; 

     // Find the first line with a non-white pixel 
     while(r) { 
      r--; 
      for(c = 0; c < width; c++) { 
       if(data[r * width * 4 + c * 4 + 3]) { 
        first = r; 
        break; 
       } 
      } 

      // If we've got it then return the height 
      if(first != r) return 99 - first; 
     } 

     // We screwed something up... What do you expect from free code? 
     return 0; 
    } 
    ctx.baseline = "Alphabetic"; 
    ctx.font= "36px arial"; 
    var height = measureTextHeight(0, 0, canvas.width, canvas.height,text); 
    //return the height of the string 
    return height; 
} // end $(function(){}); 

Von dort habe ich einfach die folgende Einstellung zur y, um den Text zu Mitte zum Ausgleich:

var textheight = fontheight(inputtext); //Calculate Text Height 
var textheight2 = fontheight2(inputtext); //Calculate portion above the baseline 
var difference = textheight - textheight2; // Calculate the portion below the baseline 
var y = 100 - difference + textheight/2; // Adjust the y cordinate 

Dadurch wird die y-Offset für den Teil des Textes anzupassen, die unter dem Textbaseline ist . Ich habe den JSFiddle hier aktualisiert http://jsfiddle.net/grapien/R6DWN/6/.

0

Sie können diese link betrachten. Ein Text-Wrapper wird verwendet.

+0

Ich verwende diesen Code tatsächlich auf meiner Webseite, aber er ist nicht dynamisch, da alle Variablen vom Benutzer voreingestellt sind (z. B. Zeilenhöhe und y) und nicht im Handumdrehen berechnet werden. Ich habe mehrere Zeilen des Codes entfernt, da das Problem nicht gelöst werden muss. Das eigentliche Problem ist, dass es keine Textdatenbank gibt, die auf dem vom Benutzer eingegebenen Text basiert, sondern die verwendete Schriftbibliothek. Dies führt zu einem anderen Offset basierend auf dem, was der Benutzer eingegeben hat. Das größere Problem ist, wie man diesen Offset dynamisch berechnet. – grapien

+0

Ja, ich habe Sie getestet Fiddle-Code, und die Text-Baseline schwebt um 25 ~ 32. Als eine sehr einfache Problemumgehung würde ich die Zeilenhöhe von "Yy" anstelle des Benutzertextes nehmen. Dann hätten Sie eine solide Basislinie, die sich nicht ändern würde.Es ist nicht sehr elegant, obwohl –

+0

Ich habe es geschafft, herauszufinden, wie dynamisch der Code meine Antwort unten zu testen. Er nimmt die Zeichenfolge und berechnet den Teil der Zeichenfolge, der unter der Basislinie liegt, indem er die Differenz berechnet. Ich kann dann diesen Unterschied in der Variable y berücksichtigen, um die Platzierung des Textes anzupassen. – grapien

Verwandte Themen