webentwicklung-frage-antwort-db.com.de

Zeichnen von gedrehtem Text auf einer HTML5-Leinwand

Für einen Teil einer Webanwendung, die ich gerade entwickle, muss ich Balkendiagramme erstellen, um verschiedene Informationen anzuzeigen. Ich dachte mir, wenn der Browser des Benutzers in der Lage ist, würde ich sie mit dem HTML5-Canvas-Element zeichnen. Ich habe kein Problem damit, Linien und Balken für meine Diagramme zu zeichnen, aber beim Beschriften der Achsen, der Balken oder der Linien bin ich in einen Haken geraten. Wie zeichne ich gedrehten Text auf ein Leinwandelement, so dass er mit dem von ihm beschrifteten Element übereinstimmt? Einige Beispiele sind:

  • Drehen Sie den Text um 90 Grad gegen den Uhrzeigersinn, um die y-Achse zu beschriften
  • Drehen Sie den Text um 90 Grad gegen den Uhrzeigersinn, um die Balken in einem vertikalen Diagramm zu kennzeichnen
  • Drehen Sie den Text um einen beliebigen Betrag in Beschriftungslinien in einem Liniendiagramm

Alle Hinweise wären dankbar.

55
Sparafusile

Wie andere bereits erwähnt haben, möchten Sie wahrscheinlich eine vorhandene Grafiklösung wiederverwenden. Das Drehen von Text ist jedoch nicht allzu schwierig. Das etwas verwirrende (für mich) ist, dass Sie den gesamten Kontext drehen und dann darauf zeichnen:

ctx.rotate(Math.PI*2/(i*6));

Der Winkel ist im Bogenmaß . Der Code ist aus diesem Beispiel entnommen , von dem ich glaube, dass er für den Transformations-Teil des MDC-Canvas-Tutorials erstellt wurde .

Bitte sehen Sie die Antwort unten für eine umfassendere Lösung.

33
robertc

Veröffentlichen Sie dies, um anderen mit ähnlichen Problemen zu helfen. Ich habe dieses Problem mit einem fünfstufigen Ansatz gelöst: Speichern Sie den Kontext, übersetzen Sie den Kontext, drehen Sie den Kontext, zeichnen Sie den Text und stellen Sie den Kontext wieder in den gespeicherten Zustand. 

Ich denke an Übersetzungen und wandle mich in den Kontext um, indem ich das auf der Leinwand liegende Koordinatenraster manipuliere. Standardmäßig beginnt der Ursprung (0,0) in der oberen linken Ecke der Leinwand. X steigt von links nach rechts, Y steigt von oben nach unten. Wenn Sie mit Ihrer linken Hand ein "L" mit Ihrem Zeigefinger und Daumen machen und es mit Ihrem Daumen nach unten halten, zeigt Ihr Daumen in Richtung des zunehmenden Y und der Zeigefinger in die Richtung Ich weiß, dass es elementar ist, aber ich finde es hilfreich, wenn ich über Übersetzungen und Rotationen nachdenke. Hier ist der Grund:

Wenn Sie den Kontext übersetzen, verschieben Sie den Ursprung des Koordinatenrasters an eine neue Position auf der Leinwand. Denken Sie beim Drehen des Kontextes daran, das mit der linken Hand erstellte "L" im Uhrzeigersinn um den Betrag zu drehen, der durch den Winkel angegeben wird, den Sie im Bogenmaß um den Ursprung angeben. Geben Sie beim StrokeText oder FillText Ihre Koordinaten in Bezug auf die neu ausgerichteten Achsen an. Um Ihren Text so auszurichten, dass er von unten nach oben lesbar ist, würden Sie ihn an eine Position verschieben, an der Sie Ihre Beschriftungen beginnen möchten, um -90 Grad drehen und Füll- oder Strichtext ausfüllen, um jedes Beschriftungselement entlang der gedrehten x-Achse zu verschieben. So etwas sollte funktionieren:

 context.save();
 context.translate(newx, newy);
 context.rotate(-Math.PI/2);
 context.textAlign = "center";
 context.fillText("Your Label Here", labelXposition, 0);
 context.restore();

.restore () setzt den Kontext auf den Zustand zurück, den Sie beim Aufruf von .save () hatten - praktisch, um die Dinge auf "normal" zurückzusetzen.


110
user631644

Dies ist zwar eine Art Nachfolge der vorherigen Antwort, fügt jedoch ein wenig (hoffentlich) hinzu.

Hauptsächlich möchte ich klarstellen, dass wir normalerweise daran denken, Dinge wie draw a rectangle at 10, 3 zu zeichnen.

Wenn wir also so denken: move Origin to 10, 3, dann draw rectangle at 0, 0____. Dann müssen wir nur noch eine Drehung dazwischen einfügen.

Ein weiterer wichtiger Punkt ist die Ausrichtung des Textes. Es ist am einfachsten, den Text mit 0, 0 zu zeichnen. Wenn Sie die korrekte Ausrichtung verwenden, können Sie dies auch ohne Messung der Textbreite tun.

Wir sollten den Text trotzdem um einen Betrag verschieben, damit er vertikal zentriert wird, und leider hat Canvas keine großartige Unterstützung für die Zeilenhöhe. Das ist also eine Vermutung und eine Überprüfung (korrigieren Sie mich, wenn etwas besseres ist).

Ich habe drei Beispiele erstellt, die einen Punkt und einen Text mit drei Ausrichtungen enthalten, um zu zeigen, wo sich die Schrift tatsächlich auf dem Bildschirm befindet.

enter image description here

var font, lineHeight, x, y;

x = 100;
y = 100;
font = 20;
lineHeight = 15; // this is guess and check as far as I know
this.context.font = font + 'px Arial';


// Right Aligned
this.context.save();
this.context.translate(x, y);
this.context.rotate(-Math.PI / 4);

this.context.textAlign = 'right';
this.context.fillText('right', 0, lineHeight / 2);

this.context.restore();

this.context.fillStyle = 'red';
this.context.fillRect(x, y, 2, 2);


// Center
this.context.fillStyle = 'black';
x = 150;
y = 100;

this.context.save();
this.context.translate(x, y);
this.context.rotate(-Math.PI / 4);

this.context.textAlign = 'center';
this.context.fillText('center', 0, lineHeight / 2);

this.context.restore();

this.context.fillStyle = 'red';
this.context.fillRect(x, y, 2, 2);


// Left
this.context.fillStyle = 'black';
x = 200;
y = 100;

this.context.save();
this.context.translate(x, y);
this.context.rotate(-Math.PI / 4);

this.context.textAlign = 'left';
this.context.fillText('left', 0, lineHeight / 2);

this.context.restore();

this.context.fillStyle = 'red';
this.context.fillRect(x, y, 2, 2);

Die Zeile this.context.fillText('right', 0, lineHeight / 2); ist im Grunde 0, 0, nur bewegen wir uns etwas, damit der Text in der Nähe des Punktes zentriert wird

22
Funkodebat

Hier ist eine HTML5-Alternative zu Homebrew: http://www.rgraph.net/ Möglicherweise können Sie ihre Methoden zurückentwickeln ...

Sie können auch etwas wie Flot ( http://code.google.com/p/flot/ ) oder GCharts in Betracht ziehen: ( http://www.maxb.net/scripts/jgcharts/include/demo/# 1 ) Es ist nicht ganz so cool, aber vollständig abwärtskompatibel und unheimlich einfach zu implementieren.

0
bpeterson76

Funkodebat hat eine großartige Lösung geposted, auf die ich oft verwiesen habe ... __ Trotzdem schreibe ich jedes Mal, wenn ich das brauche, mein eigenes Arbeitsmodell ... Hier ist mein Arbeitsmodell ... mit etwas mehr Klarheit.

Vor allem ist die Höhe des Texts gleich der Pixel-Schriftgröße . Nun, das habe ich vor einiger Zeit gelesen, und das hat sich in meinen Berechnungen herausgestellt. Ich bin nicht sicher, ob dies mit allen Schriftarten funktioniert, aber es scheint mit Arial, serifenlos, zu funktionieren.

Um sicherzustellen, dass Sie den gesamten Text in Ihre Leinwand einpassen (und nicht die Enden Ihrer "p" s abschneiden), müssen Sie context.textBaseline * einstellen.

Im Code sehen Sie, dass wir den Text um seine Mitte drehen. Um dies zu tun, müssen Sie context.textAlign = "center" und die context.textBaseline nach unten setzen. Ansonsten schneiden wir Teile unseres Textes ab.

Warum die Größe der Leinwand ändern? Ich habe normalerweise eine Leinwand, die nicht an die Seite angehängt wird. Ich zeichne damit meinen gesamten gedrehten Text, dann zeichne ich ihn auf eine andere Leinwand, die ich anzeigt ... Sie können mit dieser Leinwand beispielsweise alle Beschriftungen für ein Diagramm (eine nach der anderen) zeichnen und das Zeichen zeichnen verborgene Leinwand auf der Diagrammfläche, wo Sie die Beschriftung benötigen (context.drawImage(hiddenCanvas, 0, 0);).

WICHTIGER HINWEIS: Stellen Sie Ihre Schriftart ein, bevor Sie den Text messen, und wenden Sie nach dem Ändern der Größe der Leinwand Ihren gesamten Stil auf den Kontext an. Der Kontext einer Leinwand wird vollständig zurückgesetzt, wenn die Größe der Leinwand geändert wird.

Hoffe das hilft!

var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
var font, text, x, y;

text = "Mississippi";

//Set font size before measuring
font = 20;
ctx.font = font + 'px Arial, sans-serif';
//Get width of text
var metrics = ctx.measureText(text);
//Set canvas dimensions
c.width = font;//The height of the text. The text will be sideways.
c.height = metrics.width;//The measured width of the text
//After a canvas resize, the context is reset. Set the font size again
ctx.font = font + 'px Arial';
//Set the drawing coordinates
x = font/2;
y = metrics.width/2;
//Style
ctx.fillStyle = 'black';
ctx.textAlign = 'center';
ctx.textBaseline = "bottom";
//Rotate the canvas and draw the text
ctx.save();
ctx.translate(x, y);
ctx.rotate(-Math.PI / 2);
ctx.fillText(text, 0, font / 2);
ctx.restore();
<canvas id="myCanvas" width="300" height="150" style="border:1px solid #d3d3d3;">

0
WebWanderer