Dibujar text girado en un canvas de HTML5

Parte de una aplicación web que estoy desarrollando me obliga a crear charts de barras para mostrar información diversa. Pensé que, si el browser del usuario es capaz, los dibujaría usando el elemento Canvas de HTML5. No tengo problemas dibujando líneas y barras para mis charts, pero cuando se trata de labelr los ejes, las barras o las líneas, me encontré con un problema. ¿Cómo dibujo text girado en un elemento canvas para que se alinee con el elemento que está labelndo? Un par de ejemplos incluyen:

  • Gire el text 90 grados en sentido antihorario para labelr el eje y
  • Gire el text 90 grados en sentido antihorario para labelr barras en un gráfico de barras verticales
  • Girar text en una cantidad arbitraria para labelr líneas en un gráfico de líneas

Cualquier indicador sería apreciada.

Al igual que otros han mencionado, es probable que desee considerar reutilizar una solución gráfica existente, pero rotar el text no es demasiado difícil. La parte algo confusa (para mí) es que rotan todo el context y luego dibujan sobre él:

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

El ángulo está en radianes . El código está tomado de este ejemplo , que creo que fue hecho para la parte de transformaciones del tutorial de canvas de MDC .

Consulte la respuesta a continuación para get una solución más completa.

Publicar esto en un esfuerzo por ayudar a otros con problemas similares. Resolví este problema con un enfoque de cinco pasos: save el context, traducir el context, rotar el context, dibujar el text y luego restaurar el context a su estado guardado.

Pienso en las traducciones y las transformaciones al context como la manipulación de la cuadrícula de coorderadas superpuesta en el canvas. Por defecto, el origen (0,0) comienza en la esquina superior izquierda del canvas. X aumenta de izquierda a derecha, Y aumenta de arriba a abajo. Si haces una "L" con el dedo índice y el pulgar en tu mano izquierda y la sostienes frente a ti con el pulgar hacia abajo, tu pulgar apuntará en la dirección de boost Y y tu dedo índice apuntará en la dirección de boost X. Sé que es elemental, pero me parece útil cuando pienso en las traducciones y las rotaciones. Este es el por qué:

Cuando traduce el context, mueve el origen de la cuadrícula de coorderadas a una nueva location en el canvas. Cuando gire el context, piense en girar la "L" que hizo con la mano izquierda en el sentido de las agujas del reloj, la cantidad indicada por el ángulo que especifique en radianes sobre el origen. Cuando aplique strokeText o fillText, especifique sus coorderadas en relación con los ejes recién alineados. Para orientar el text de modo que sea legible de abajo hacia arriba, se traduciría a una position debajo de donde desea comenzar sus tags, rotará en -90 grados y rellenará o acariciará el text, desplazando cada label a lo largo del eje x girado. Algo como esto debería funcionar:

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

.restre () restablece el context al estado que tenía cuando llamó a .save () – útil para devolver las cosas a "normal".


Si bien esto es una especie de seguimiento a la respuesta anterior, agrega un poco (con suerte).

Principalmente lo que quiero aclarar es que generalmente pensamos dibujar cosas como draw a rectangle at 10, 3 .

Entonces, si pensamos en eso de esta manera: move origin to 10, 3 , luego draw rectangle at 0, 0 . Entonces todo lo que tenemos que hacer es agregar un giro en el medio.

Otro gran punto es la alignment del text. Es más fácil dibujar el text en 0, 0, por lo que usar la alignment correcta puede permitirnos hacer eso sin medir el ancho del text.

Todavía deberíamos mover el text en una cantidad para centrarlo verticalmente, y desafortunadamente el canvas no tiene soporte de gran altura de línea, así que eso es una cuestión de adivinar y verificar (corríjanme si hay algo mejor).

He creado 3 ejemplos que proporcionan un punto y un text con 3 alineaciones, para mostrar cuál es el punto real en la pantalla donde irá la fuente.

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.restre(); this.context.fillStyle = 'networking'; 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.restre(); this.context.fillStyle = 'networking'; 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.restre(); this.context.fillStyle = 'networking'; this.context.fillRect(x, y, 2, 2); 

La línea this.context.fillText('right', 0, lineHeight / 2); es básicamente 0, 0 , excepto que nos movemos ligeramente para que el text se centre cerca del punto

Aquí hay una alternativa HTML5 a homebrew: http://www.rgraph.net/. Es posible que pueda realizar una ingeniería inversa de sus methods …

También podría considerar algo como Flot ( http://code.google.com/p/flot/ ) o GCharts: ( http://www.maxb.net/scripts/jgcharts/include/demo/#1 ) No es bastante genial, pero totalmente compatible con versiones anteriores y aterrador, fácil de implementar.