2010-07-02 122 views
46

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

  • 旋轉文本90度逆時針 標記y軸
  • 旋轉文本90度計數器 順時針標記在垂直 條形圖條
  • 旋轉文本的任意相當於 線條上的標籤線

任何指針,將不勝感激。

+0

你有沉吟尋找到現有的繪圖解決方案,而不是試圖建立自己的? flot(http://code.google.com/p/flot/)是一個使用畫布的例子。 – Bartek 2010-07-02 17:47:29

回答

98

發佈此信息旨在幫助其他類似問題的人。我用五步法解決了這個問題 - 保存上下文,翻譯上下文,旋轉上下文,繪製文本,然後將上下文恢復到其保存的狀態。

我想到翻譯和轉換到上下文作爲操縱覆蓋在畫布上的座標網格。默認情況下,原點(0,0)從畫布的左上角開始。 X從左到右增加,Y從上到下增加。如果您用左手的食指和拇指做出「L」,並用拇指向下握住它,拇指指向Y方向,食指指向方向增加X.我知道這是基本的,但我覺得在思考翻譯和旋轉時很有幫助。原因如下:

翻譯上下文時,將座標網格的原點移動到畫布上的新位置。當旋轉上下文時,考慮用左手旋轉「L」,順時針方向旋轉由弧度指定的原點所指示的角度。當您使用strokeText或fillText時,請指定與新對齊軸相關的座標。爲了定位文本,使其可以從下到上讀取,您可以將它翻譯到低於您想要開始標籤的位置,旋轉-90度並填充或strokeText,使每個標籤沿旋轉的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()狀態 - 方便返回的東西回到「正常」。


+2

偉大的翻譯/旋轉說明。 +1 – 2013-06-28 00:41:23

+6

如果你想設置角度爲特定的東西,你可以這樣做: 'context.rotate(angle *(Math.PI/180));' – PaulBGD 2014-08-23 06:33:05

+0

不止這些代碼,我愛你的解釋。 – Sorter 2017-03-09 12:59:17

21

雖然這是前面的答案的後續行動,但它增加了一點(希望)。

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

所以,如果我們這樣想:move origin to 10, 3,然後draw rectangle at 0, 0。 然後,我們所要做的就是在兩者之間添加一個旋轉。

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

我們仍然應該將文字移動一定數量以垂直居中,不幸的是畫布沒有很高的線條高度支持,所以這是一個猜測和檢查的事情(糾正我,如果有更好的東西)。

我已經創建了3個示例,提供了一個點和一個帶有3個對齊方式的文本,以顯示屏幕上的實際點是什麼字體的位置。

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

this.context.fillText('right', 0, lineHeight/2);基本上是0, 0,除了我們的文本稍微動點附近爲中心