Un poco de trigonometría para crear un menú circular con HTML5

Tamaño de letra:

Menú circular con CSS3 o SVG

Este artículo puede ser interesante para aquellas personas que no adoran mucho las matemáticas y, sin embargo, les gusta el diseño y tal vez quieran centrarse en diseño web. Ciertamente ambos conceptos pueden ir muy relacionados como seguidamente vamos a ver y tal vez a partir de ahora, te sientas un poco más atraído por esta ciencia.

Hace un tiempo me propuse realizar un menú circular con HTML5 y CSS3: un círculo relleno de sectores, como una caja de quesitos vista desde arriba. Veamos la imagen final que me quedó:

Menú circular con sectores

Realizar el menú de la imagen anterior solo con CSS es complejo porque tras buscar mucha información e intentarlo (en la mayoría de ellos se suele realizar con la propiedad transform), no todos los navegadores responden igual y se necesitan hacks para que se vea correcto en todos ellos. Es por ello que decidí realizarlo con gráficos vectoriales escalables (SVG: Scalable Vector Graphics) y aún di un paso más utilizando la librería Raphaeljs que tiene una excelente compatibilidad con navegadores antiguos, aparte de otras ventajas. Pero hoy no es el día de hablar de esto.

Detalles del diseño, punto (0,0) del eje de coordenadas

Si imaginamos un eje de coordenadas, el punto (0,0) se encuentra (en este caso) en el vértice superior izquierdo 1. Algunos de los detalles importantes que puedes ver son:

  • Entre el eje horizontal que pasa por el punto (0,0) y el inicio de la circunferencia existe un distancia: distTop. Lo mismo con el eje vertical: distLeft.
  • Cada sector tiene un color específico y un menú específico. Los 8 sectores tienen el mismo tamaño.
  • Si te fijas en el sector "Menú 2" verás que no se inicia en la misma vertical, sino que ha sido girado unos grados.
  • El texto de los sectores tiene distintas inclinaciones y hay que posicionarlos aproximadamente en el centro del sector.
  • La circunferencia tiene un radio: "radio" y un diámetro: "2radio".

Dibujar los sectores con SVG

Para el dibujo de cada sector yo me decidí por hacer uso del elemento <path>, aunque programado desde Raphaeljs es un pelín diferente. ¡Empecemos! Para entenderlo y simplificar el problema, distTop y distLeft los voy a poner con valor 0 y el valor del radio lo voy a poner de ejemplo a 200 píxeles (el rectángulo de fondo negro es de 400 x 400 px). Vamos a comenzar con el sector del "Menú 2":

Sector del menú 2

Si me imagino que estoy en el punto (0,0) -esquina superior izquierda- y quiero dibujar el "Menú 2" le diría las siguientes instrucciones:

1.- Ve al centro de la circunferencia

Posiciónate en el centro de la circunferencia 2. Para eso muevo tanto la x como la y el valor del radio: de (0,0) a (200, 200).

Esto con SVG se traduce en: M 200 200

2.- Posición del punto 3

Hay que calcular la posición del punto 3 para realizar la recta 2-3. Tomando como referencia el punto (0,0). ¿Cuáles son las coordenadas exactas del punto 3? Yo me ayudo de la trigonometría e intento buscar un triángulo rectángulo pero para ello hago uso del ángulo que forma la línea 2-3 con la horizontal 2-5. El triángulo que imagino es el formado por los puntos: 2, 6 y 3.

Triángulo rectángulo en el menú 2

Como hemos visto hay 8 sectores (8 menús dentro del círculo), por lo tanto cada sector tiene un ángulo de 360º/8 = 45º.

Normalmente se suele trabajar con radianes en vez de grados sexagesimales, así que como PI radianes = 180º, 45º = PI/4 rad.

¿Cuánto vale el ángulo formado por las líneas 2-3 y 2-6? Es bastante sencillo porque el sector en rojo tiene ?/4 rad, con lo cual si lo dividimos por la mitad, esa nueva línea que se creará en la vertical del punto 2 formará un ángulo con la horizontal 2-5 de ?/2 rad. En resumen ?/2 - ?/8 = 3/8? rad.

Primer dato: ángulo líneas 2-3 y 2-6 = 3/8? rad

Debemos calcular ahora la distancia 2-6, usando trigonometría sabemos que el coseno del ángulo 2-3 y 2-6 es igual a la distancia 2-6 dividido por la hipotenusa 2-3 (el radio de la circunferencia).

cos 3/8? =
distancia 2-6 / radio
=
distancia 2-6 / 200px

Con lo que la distancia 2-6 es igual a cos 3/8? x 200 = 76,54 px (aprox).

Del mismo modo hay que calcular la distancia 3-6. Viendo el triángulo rectángulo anterior, tenemos que sin 3/8? = distancia 3-6 / radio; distancia 3-6 = 184,78 px (aprox).

Reunir todos los datos para dibujar con SVG

Coordenadas del punto 3:

  • x = radio + distancia 2-6 = 200 + 76,54 = 276,54 píxeles.
  • y = radio - distancia 3-6 = 200 - 184,78 = 15,22 píxeles.

Para dibujar una línea usando SVG podemos hacerlo con L 276.54 15.22

3.- Obtener las coordenadas del punto 4 y hacer un arco.

El ángulo entre 2-4 y 2-5 es de 112,5º = 5/8?. ¿Y ahora qué hacemos con un ángulo mayor de ?/2? Esto es interesante porque la línea 2-4 se encuentra en el segundo cuadrante de la circunferencia y como sabrás un triángulo rectángulo no puede tener un ángulo mayor de 90 grados sexagesimales.

Ángulo trigonometría en segundo cuadrante

Del mismo modo anterior, podemos ver un triángulo rectángulo 2-4-7. Sin embargo, tenemos el ángulo formado por las líneas 2-4 y 2-5 de 112,5º = 5/8?. Hay que intentar simplificar el problema, ya que vemos rápidamente que podemos obtener el ángulo del triángulo rectángulo ya que son suplementarios, no obstante, cuando programas no sabes si el ángulo está en primer, segundo, tercer o cuarto cuadrante. Por lo tanto, el cálculo del ángulo suplementario no nos va a resultar "demasiado" útil.

Es por eso que me decido a usar las razones trigonométricas seno y coseno. Ya verás que nos van a simplificar el problema a la mínima expresión. En cualquiera de los 4 cuadrantes de la circunferencia:

Si piensas en una circunferencia unitaria el seno es la ordenada que corresponde a ese punto y el coseno la abscisa.

Por lo tanto, la distancia 2-7 en una circunferencia unitaria, donde su radio vale 1, equivaldría a: cos (2-5 2-4), donde obtendríamos un valor negativo. ¿Y si la circunferencia no es unitaria, como es el ejemplo de hoy? Se cumple -observa la imagen anterior- que:

cos (2-5 2-4) =
distancia 2-7 / radio

Por lo tanto, finalmente obtenemos que:

distancia (2-7) = cos (2-5 2-4) x radio

En el ejemplo, distancia (2-7) = cos 5/8? x 200píxeles = -0,3827 x 200 = -76,53 píxeles

Y la distancia (7-4) = sen 5/8? x 200píxeles = 0,92 x 200 = 184,76 píxeles

Coordenadas del punto 4:

  • x = radio - distancia 2-7 = 200 - 76,53 = 123,47 píxeles.
  • y = radio - distancia 7-4 = 200 - 184,76 = 15,24 píxeles.

Las operaciones matemáticas anteriores están hechas para orientarse visualmente. No pienses, de momento, en el signo + o - de la distancia.

Dibujando la curva con SVG

Para realizar un arco con SVG utilizaremos la letra A: arco elíptico

A: rx,ry x-axis-rotation large-arc-flag sweep-flag x,y. Unos valores que podemos dar son los siguientes:

A200,200,0,0,0,123.47,15.24

Dibujando el sector con SVG

El código final reagrupando todo es:

M200,200L276.54,15.22A200,200,0,0,0,123.47,15.24Z

Y el ejemplo real (debes verlo en un navegador que admita SVG) el siguiente:

Puedes ver y editar el ejemplo tú mismo desde aquí:

Código para situar cualquier punto

Como hemos visto antes, calcular las coordenadas x e y de cualquier punto después de haber entendido todo lo que he comentado hoy, se reduce a una operación muy sencilla:

  • Situarnos en el centro de la circunferencia
  • La distancia en el eje de abscisas (X) al centro será: coseno(ángulo) x radio(circunferencia).
  • La distancia en el eje de ordenadas (Y) al centro será: seno(ángulo) x radio(circunferencia).

De este modo serás capaz de dibujar sencillamente una circunferencia dividida en sectores. Aún quedaría calcular la posición exacta de los ítems, por ejemplo, no tiene la misma longitud "www.karmany.net" que "Menú 2". Pero eso lo dejaré para otro día, que este artículo está quedando muy largo.

Última actualización: Viernes, 25 Septiembre 2015
Escribir un comentario
Antes de publicar un comentario, usted debe aceptar nuestras condiciones de uso: Condiciones de uso. Debido al spam, todos los comentarios serán moderados. Normalmente se responde en unos minutos, refresca los comentarios para comprobarlo.



 
Visitas: 8490547