Practicando con D3.js y datos del IBEX35 – Parte V

En esta nueva versión de la gráfica quiero que, cuando el usuario mueva el ratón sobre la gráfica, se muestre en un popup el valor sobre el que está posicionado el ratón. Para ello, tendré que usar el evento mouseover de d3.js.

El resultado final

El resultado final es el siguiente (si movéis el ratón sobre la gráfica, debe aparecer un popup con el valor sobre el que estáis):

Podéis abrir este mismo resultado en una ventana independiente aquí.

El código html

El código html no ha experimentado ningún cambio respecto de la versión anterior.

El código css

El código css ha variado un poco … pero permitidme que, esta vez, no explique los cambios hasta el final de esta entrada.

El código javascript

Primero, como siempre, el código javascript completo:

Vamos a ver ahora los puntos más interesantes

Definiciones iniciales y definición del slider

La primera parte de las definiciones iniciales, son iguales a las de la versión anterior:

A continuación, viene la definición de dos elemento svg nuevos:

Vemos que hemos añadido dos nuevos elementos:

  • Un elemento g al que hemos asignado la clase popup-area. Este elemento, será el que usemos para mostrar en él la información del popup.
  • Un elemento rect al que hemos asignado la clase mouseover-area.

La función de este nuevo rect será cubrir todo el área de la gráfica. Una vez que la cubra, activaremos sobre este elemento el evento mouseover de modo que así sabremos cuándo el usuario está sobre la gráfica para mostrar el popup.

Quizás la creación de este elemento necesite una explicación. Está claro que necesitábamos programar el evento mouseover sobre alguno de los elementos svg de nuestra gráfica. Pero:

  • Si lo programábamos sobre el elemento svg contenedor de todo, éste también incluía cuando se movía el ratón sobre los ejes de coordenadas. Y el efecto no quedaba bien.
  • Si lo programábamos sobre la elemento path de la gráfica, no funcionaba.
  • Sin embargo, si creamos un elemento rect que cubra todo el cuadrante de la gráfica, ése es el espacio sobre el que quiero activar el mouseover.
  • Además, configuraré este nuevo elemento rect de color transparente, para que sea invisible para el resto de la gráfica.

Otro punto importante es que primero defino el elemento g que voy a usar para contener del popup y después defino el elemento rect. El motivo para este orden concreto es más sutil:

  • En svg, no existe el concepto de capas (como el elemento z-index de css). De modo que si dos elementos svg coinciden en la misma posición, estará en primer plano el elemento que se haya definido el último.
  • Como he explicado, mi elemento rect cubre todo el área de la gráfica y estoy pendiente de su evento mouseover para mostrar el elemento g que contendrá el popup con la información del punto. Pero si este elemento g lo posiciono por delante de mi elemento rect –> si muevo el ratón sobre el popup, éste ocultará al elemento rect y no se disparará el evento mouseover.
  • Así pues, en el orden en que los he creado, el elemento rect estará en primer plano respecto del elemento g y éste último no interceptará al evento mouseover cuando el mueva el ratón por encima.
  • Pero, si el elemento rect está en primer plano ¿no ocultará al elemento g del popup?. No lo hará, porque ya expliqué antes que el he configurado el elemento rect de color transparente. Así que el popup se verá sin problemas.

Captura del movimiento del ratón

Ahora, viene la parte del código realmente nueva:

Vamos a estudiar este código, paso a paso. Primero, programo el evento mouseout para que cuando el ratón abandone la zona de la gráfica, borre el contenido del elemento g que contiene el popup:

Después, programo la captura del movimiento del ratón sobre la gráfica:

Obtengo la posición sobre la que está el ratón de la propiedad d3.mouse(this)[0]. Para calcular a qué fecha corresponde esta posición, uso mi escala horizontal xRange. Como vemos, una escala no solo sirve para mapear valores a posiciones, sino también para el proceso inverso (usando el método invert). A la posición del ratón, le debo restar el margen izquierdo. También le resto 5 (es un valor que he calculado tanteando, porque parece que la posición devuelta por clientX no coincide con la punta del ratón.

Una vez que tengo la fecha asociada a la posición del ratón, busco en mi lista de datos la fecha más aproximada para la que tengo datos.

Por fin, una vez que ya tengo calculado el punto que quiero mostrar (su fecha en la variable pointDate y su valor en la variable pointValue) lo único que falta es borrar el contenido previo del elemento g que he elegido para contener el popup (y que ya tengo referenciado en la variable popupArea) y añadirle dentro un pequeño círculo centrado en el punto que hemos calculado y el nuevo popup con estos datos:

Para mostrar el valor uso el método d3.format al que le paso una especificación y me devuelve un formateador. Una vez que paso el valor por el formateador, tenemos el problema de que este formateador sólo está preparado para cifras en dólares y formato americano. Por eso, antes de mostrarla, convierto el valor formatado a euros y formato español.

También vemos que a cada elemento le he asignado clases específicas (y que usaremos en nuestro fichero css).

Dibujo e inicialización de la gráfica

La última parte del código (donde dibujo la gráfica e inicializo la gráfica), es exactamente igual a la versión anterior.

La única diferencia, es que también debo configurar el nuevo elemento rect sobre el que he explicado que he programado la captura del ratón (referenciado por la variable mouseOverArea) para que cubra toda la anchura de la gráfica (excepto los márgenes)

El código css

Si estudiáis el nuevo código, comprobaréis que no tengo especificado ningún tipo de información sobre colores. El motivo es que esta información la he incluido dentro del fichero css:

Efectivamente, mis elementos svg forman parte del DOM del documento y por lo tanto puedo aplicarles reglas css:

  • El rectángulo que contendrá el popup (identificado por la clase popup-text) lo he configurado de color verde y un poco transparente.
  • He configurado los textos de la fecha y el valor (identificados por las clases point-date y point-value, respectivamente).
  • El circulito que me resaltará el punto (de clase popup-circle) lo he configurado también de color verde.
  • Y, sobre todo, he configurado el rectángulo sobre el que he capturado el ratón (de la clase mouseover-area) para que sea transparente.

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

*
*
Sitio Web