簡體   English   中英

在 HTML5 畫布上繪制旋轉文本

[英]Drawing rotated text on a HTML5 canvas

我正在開發的 Web 應用程序的一部分要求我創建條形圖來顯示各種信息。 我想,如果用戶的瀏覽器有能力,我會使用 HTML5 畫布元素繪制它們。 我為我的圖形繪制線條和條形沒有問題,但是在標記軸、條形或線條時,我遇到了障礙。 如何將旋轉的文本繪制到畫布元素上,使其與它所標記的項目對齊? 幾個例子包括:

  • 將文本逆時針旋轉 90 度以標記 y 軸
  • 將文本逆時針旋轉 90 度以標記垂直條形圖上的條形
  • 將文本旋轉任意量以標記折線圖上的線條

任何指針將不勝感激。

發布此信息是為了幫助其他有類似問題的人。 我用五步方法解決了這個問題——保存上下文、翻譯上下文、旋轉上下文、繪制文本,然后將上下文恢復到其保存狀態。

我認為翻譯和轉換到上下文就像操縱覆蓋在畫布上的坐標網格。 默認情況下,原點 (0,0) 從畫布的左上角開始。 X 從左到右增加,Y 從上到下增加。 如果你用左手的食指和拇指做一個“L”,然后將它放在你面前,拇指朝下,你的拇指會指向 Y 增加的方向,而你的食指會指向 Y 增加的方向增加 X。我知道這是基本的,但我發現在考慮平移和旋轉時它很有幫助。 原因如下:

平移上下文時,會將坐標網格的原點移動到畫布上的新位置。 當您旋轉上下文時,請考慮將您用左手制作的“L”沿順時針方向旋轉,該量由您指定的關於原點的弧度角指示。 當您使用strokeText 或fillText 時,請指定與新對齊的軸相關的坐標。 要調整文本方向,使其從下到上可讀,您需要將位置轉換為下方要開始標簽的位置,旋轉 -90 度並填充或筆觸文本,沿旋轉的 x 軸偏移每個標簽。 這樣的事情應該工作:

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

.restore() 將上下文重置回它在您調用 .save() 時的狀態——方便將事情恢復到“正常”。


就像其他人提到的那樣,您可能想考慮重用現有的圖形解決方案,但旋轉文本並不太困難。 有點令人困惑的一點(對我來說)是你旋轉整個上下文然后在它上面繪制:

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

角度以弧度為單位 代碼取自這個示例,我相信它是為MDC 畫布教程轉換部分制作的

請參閱下面的答案以獲得更完整的解決方案。

雖然這是對上一個答案的跟進,但它增加了一點(希望如此)。

我主要想澄清的是,通常我們會想到繪制諸如draw a rectangle at 10, 3類的東西。

因此,如果我們這樣考慮: move origin to 10, 3 ,然后draw rectangle at 0, 0 然后我們要做的就是在兩者之間添加一個旋轉。

另一個重點是文本的對齊。 在 0, 0 處繪制文本是最容易的,因此使用正確的對齊方式可以讓我們在不測量文本寬度的情況下做到這一點。

我們仍然應該將文本移動一定量以使其垂直居中,不幸的是畫布沒有很好的行高支持,所以這是一個猜測和檢查的事情(如果有更好的地方請糾正我)。

我創建了 3 個示例,它們提供了一個點和一個具有 3 個對齊方式的文本,以顯示屏幕上的實際點是字體所在的位置。

在此處輸入圖片說明

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

這行this.context.fillText('right', 0, lineHeight / 2); 基本上是0, 0 ,除了我們稍微移動以使文本在該點附近居中

Funkodebat 發布了一個很棒的解決方案,我已經多次引用了它。 盡管如此,每次我需要它時,我都會發現自己在編寫自己的工作模型。 所以,這是我的工作模型......增加了一些清晰度。

首先,文本的高度等於像素字體大小 現在,這是我前段時間讀到的東西,並且在我的計算中得到了解決。 我不確定這是否適用於所有字體,但它似乎適用於 Arial、sans-serif。

此外,為了確保您適合畫布中的所有文本(並且不要修剪掉“p”的尾部),您需要設置context.textBaseline*

您將在代碼中看到我們正在圍繞其中心旋轉文本。 為此,我們需要將context.textAlign = "center"context.textBaseline 設置為底部,否則,我們會修剪掉部分文本。

為什么要調整畫布大小? 我通常有一個未附加到頁面的畫布。 我用它來繪制所有旋轉的文本,然后將其繪制到另一個顯示的畫布上。 例如,您可以使用此畫布(一個接一個)繪制圖表的所有標簽,並將隱藏的畫布繪制到您需要標簽的圖表畫布上( context.drawImage(hiddenCanvas, 0, 0); )。

重要說明:在測量文本之前設置字體,並在調整畫布大小后將所有樣式重新應用於上下文。 調整畫布大小時,畫布的上下文將完全重置。

希望這可以幫助!

 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 context 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;">

這是自制軟件的 HTML5 替代品: http : //www.rgraph.net/您也許可以對他們的方法進行逆向工程....

你也可以考慮像 Flot ( http://code.google.com/p/flot/ ) 或 GCharts : ( http://www.maxb.net/scripts/jgcharts/include/demo/#1 ) 它不是非常酷,但完全向后兼容並且易於實現。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM