1. Web Design
  2. HTML/CSS
  3. JavaScript for Designers

Cómo hacer un diagrama de Gantt con JavaScript y CSS

En nuestras series de tutoriales sobre CSS, hemos aprendido a crear varios tipos de gráficos. Hoy aprenderemos cómo hacer un diagrama de Gantt con JavaScript.
Scroll to top

Spanish (Español) translation by Eva Collados Pascual (you can also view the original English article)

Hasta ahora en nuestras series de tutoriales, hemos aprendido cómo crear distintos tipos de gráficos incluyendo los gráficos de barras, los gráficos de termómetro, y los gráficos circulares.

Hoy continuaremos este viaje construyendo y presentando datos a través de un gráfico de Gantt. A diferencia de otros tutoriales de gráficos, haremos un uso extensivo de JavaScript para implementar distintos aspectos del gráfico. Serás capaz de usar esta base como plantilla de diagrama de Gantt para futuros proyectos.

Nota: recuerda que es perfectamente posible hacer un diagrama de Gantt con CSS puro gracias a CSS Grid Layout. ¡Descubre cómo hacer un diagrama de Gantt en este tutorial!

    El diagrama de Gantt con JavaScript que vamos a construir

    Aquí tienes la plantilla de diagrama de Gantt que vamos a crear (pulsa Rerun para verla animada). Muestra una serie de tareas, dejando claro cuando está programado su inicio a lo largo del curso de una semana, ya sea al inicio del día, o a medio camino, y cuando deben completarse:

    Please accept marketing cookies to load this content.

    ¿Qué es un diagrama de Gantt?

    Desarrollado por el ingeniero mecánico Henry Gantt en el periodo previo a la primera guerra mundial, los diagramas de Gantt fueron originalmente usados para gestionar la logística de la movilización de los soldados americanos y las municiones. Actualmente, las técnicas de los diagramas de Gantt se usan para mucho más que la guerra; de hecho los encontrarás presentes en la mayoría de los sectores. Hacen que resulte muy fácil visualizar una lista de tareas, la dependencia de esas tareas entre sí, y su estado de cumplimiento.

    “Un diagrama de Gantt es un tipo de gráfico de barras que ilustra la planificación de un proyecto. Este mapa de Gantt lista las tareas a realizar en el eje vertical, e intervalos de tiempo en el eje horizontal. La anchura de las barras horizontales del gráfico muestran la duración de la cada actividad.” – Wikipedia

    Visualización de un gráfico de GanttVisualización de un gráfico de GanttVisualización de un gráfico de Gantt
    Visualización de un gráfico de Gantt

    Los diagramas de Gantt le ofrecen a los gerentes la capacidad de gestionar proyectos, programar tareas, visualizar su progreso, delegar responsabilidades, y distribuir recursos.

    Realmente, no tienes que ser un gerente para usarlos. Cualquiera que quiera organizar sus tareas puede beneficiarse de un mapa de Gantt para visualizar sus proyectos.

    Además de usarlo como herramienta de gestión, un mapa de Gantt también pueden tener otros usos. Por ejemplo, puedes usar este enfoque en un sitio web corporativo como línea temporal para visualizar la historia de la empresa.

    Soluciones para diagramas de Gantt

    La mayoría de plataformas de gestión de proyectos utilizan los diagramas de Gantt como parte fundamental de su oferta. ClickUp, Zapier, y Monday.com son todos nombres que surgirán cuando tenga lugar un debate sobre apps para la gestión de proyectos (aunque los fundadores de Monday.com subrayan que se "enfocan en la gente, no en las tareas o los proyectos").

    Diagramas de Gantt en forma de plantilla disponibles en Envato Elements

    Con Keynote, PowerPoint, y otras aplicaciones de presentación es más que posible hacer un diagrama de Gantt para representar objetivos. Echa un vistazo a algunos diagramas de Gantt en forma de plantilla disponibles actualmente en Envato Elements.

    Diagrama de Gantt, plantilla para KeynoteDiagrama de Gantt, plantilla para KeynoteDiagrama de Gantt, plantilla para Keynote
    Diagrama de Gantt, plantilla para Keynote
    Estado de proyecto, diagrama de Gantt en forma de plantilla para KeynoteEstado de proyecto, diagrama de Gantt en forma de plantilla para KeynoteEstado de proyecto, diagrama de Gantt en forma de plantilla para Keynote
    Estado de proyecto, diagrama de Gantt en forma de plantilla para Keynote

    También existen diferentes soluciones gratuitas y premium disponibles por ahí con las que hacer un diagrama de Gantt. Podrás crear uno con Microsoft Excel, Google Sheets, una aplicación web como TeamGantt, diagramas de Gantt con JavaScript, como la biblioteca de Java Highcharts, o incluso escribiendo tu propio código.

    En este tutorial vamos a ver cómo hacer un diagrama de Gantt nosotros mismos, ¡vamos a hacer nuestro propio y sencillo diagrama de Gantt con JavaScript y CSS!

    1. Especifica el código de la estructura

    Empezaremos definiendo un elemento contenedor y dentro de el dos listados:

    • La primera lista define el rango de la plantilla del diagrama de Gantt, los datos del eje x. En nuestro caso, contendrá los días de la semana. Cada día representará el horario laboral habitual.
    • La segunda lista establece los datos de la plantilla del diagrama de Gantt, la información del eje y. En nuestro caso los datos incluirán las tareas que deben realizarse a lo largo de una semana. Cada elemento de la lista describe una tarea y viene con dos atributos personalizados: el atributo data-duration y el atributo data-color. El primer atributo define la duración de la tarea, mientras el segundo es el color de fondo de nuestro mapa de Gantt. El valor del atributo data-duration debería estar indicado en el formato [startDay]½-[endDay]½. Así que por ejemplo usaremos data-duration="tue-wed½" para una tarea que tenga que empezar el martes y terminar el miércoles al mediodía. De igual manera  data-duration="tue½-tue" describirá una tarea que deba empezar al mediodía del martes y finalizar ese mismo día.

    Empecemos a ver cómo hacer un diagrama de Gantt. En primer lugar, aquí tienes el código de la estructura necesario: 

    1
    <div class="chart-wrapper">
    
    2
      <ul class="chart-values">
    
    3
        <li>sun</li>
    
    4
        <li>mon</li>
    
    5
        <li>tue</li>
    
    6
        <li>wed</li>
    
    7
        <li>thu</li>
    
    8
        <li>fri</li>
    
    9
        <li>sat</li>
    
    10
      </ul>
    
    11
      <ul class="chart-bars">
    
    12
        <li data-duration="tue-wed" data-color="#b03532">Task</li>
    
    13
        <li data-duration="wed-sat" data-color="#33a8a5">Task</li>
    
    14
        ...
    
    15
      </ul>
    
    16
    </div>
    

    2. Aplicar estilo al diagrama de Gantt con plantilla

    Para simplificar, no hablaré de todos los estilos iniciales de restablecimiento, pero puedes consultarlos pulsando la pestaña CSS de la demo del diagrama de Gantt de la plantilla.

    El elemento contenedor del diagrama de Gantt tendrá una anchura máxima y su contenido estará horizontalmente centrado:

    1
    .chart-wrapper {
    
    2
      max-width: 1150px;
    
    3
      padding: 0 10px;
    
    4
      margin: 0 auto;
    
    5
    }
    

    El eje x

    La lista .chart-values será un contenedor flexible. Sus elementos de lista flexibles (los días) se distribuirán de igual manera a lo largo del eje principal y tendrá una anchura mínima de 80px. Como resultado de esa anchura mínima, en las pantallas pequeñas el gráfico no se estrechará más allá de ese valor, y aparecerá una barra de desplazamiento horizontal. Siéntete libre de eliminarla si no te gusta este comportamiento para tu plantilla de diagrama de Gantt.

    Para visualizar mejor los bordes izquierdo y derecho de cada elemento de la lista, usaremos su pseudoelemento ::before. Le asignaremos una altura de 510px, algo que nos asegura que se expandirá para dar cabida a todas las tareas. En lugar de establecer el valor de esta altura directamente con código, está la opción se calculará dinámicamente mediante JavaScript. Pero saltemos esta solución de momento, ya que tiene una importancia secundaria.

    Los valores del gráfico de GanttLos valores del gráfico de GanttLos valores del gráfico de Gantt
    Los valores del gráfico de Gantt

    Los estilos correspondientes de nuestra plantilla de diagrama de Gantt:

    1
    :root {
    
    2
      --divider: lightgrey;
    
    3
    }
    
    4
    5
    .chart-wrapper .chart-values {
    
    6
      position: relative;
    
    7
      display: flex;
    
    8
      margin-bottom: 20px;
    
    9
      font-weight: bold;
    
    10
      font-size: 1.2rem;
    
    11
    }
    
    12
    13
    .chart-wrapper .chart-values li {
    
    14
      flex: 1;
    
    15
      min-width: 80px;
    
    16
      text-align: center;
    
    17
    }
    
    18
    19
    .chart-wrapper .chart-values li:not(:last-child) {
    
    20
      position: relative;
    
    21
    }
    
    22
    23
    .chart-wrapper .chart-values li:not(:last-child)::before {
    
    24
      content: '';
    
    25
      position: absolute;
    
    26
      right: 0;
    
    27
      height: 510px;
    
    28
      border-right: 1px solid var(--divider);
    
    29
    }
    

    El eje y

    Los elementos (barras) de la segunda lista estarán inicialmente ocultos. En concreto, tendrán los siguientes atributos y valores, width: 0 y opacity: 0. Además, les asignaremos position: relative. Más adelante estableceremos dinámicamente su posición izquierda (left) en correspondencia con su atributo de duración  data-duration). 

    Aquí tienes los estilos relacionados del mapa de Gantt:

    1
    :root {
    
    2
      --white: #fff;
    
    3
    }
    
    4
    5
    .chart-wrapper .chart-bars li {
    
    6
      position: relative;
    
    7
      color: var(--white);
    
    8
      margin-bottom: 15px;
    
    9
      font-size: 16px;
    
    10
      border-radius: 20px;
    
    11
      padding: 10px 20px;
    
    12
      width: 0;
    
    13
      opacity: 0;
    
    14
      transition: all 0.65s linear 0.2s;
    
    15
    }
    
    16
    17
    @media screen and (max-width: 600px) {
    
    18
      .chart-wrapper .chart-bars li {
    
    19
        padding: 10px;
    
    20
      }
    
    21
    }
    

    3. Añade al mapa de Gantt el JavaScript 

    Cuando la página se cargue, o la ventana del navegador se redimensione, la función createChart será ejecutada: 

    1
    window.addEventListener("load", createChart);
    
    2
    window.addEventListener("resize", createChart);
    

    Nota: Como he mencionado en otros tutoriales, existen diversas formas de limitar los eventos de redimensionado (resize) que sean emitidos. Por ejemplo, una solución eficaz consiste en usar la función Lodash _.debounce . Aunque esto queda fuera del ámbito de este tutorial. 

    Dentro de esta función, hacemos primero las siguientes cosas:

    1. Cogemos los elementos de los dos listados.
    2. Convertimos la NodeList days en una cadena real usando el operador spread (operador de propagación). Alternativamente, podríamos haber usado el método Array.from(). Esta conversión nos permitirá beneficiarnos del método filter(), el cual está disponible en cadenas, para filtrar los días.
    3. Recorremos las tareas.
    1
    function createChart(e) {
    
    2
      // 1
    
    
    3
      const days = document.querySelectorAll(".chart-values li");
    
    4
      const tasks = document.querySelectorAll(".chart-bars li");
    
    5
      // 2
    
    
    6
      const daysArray = [...days];
    
    7
      // 3
    
    
    8
      tasks.forEach(el => {
    
    9
        ...
    
    10
      });
    
    11
    }
    

    Recorrer las tareas de Gantt con plantilla

    A continuación, para cada tarea del diagrama de Gantt con plantilla:

    1. Cogemos el valor de su atributo data-duration (por ej. martes-miércoles). Además, separamos este valor usando un "-" como separador.
    2. La primera cadena del array devuelto representa el primer día de la tarea (por ej. martes), mientras que el segundo es su día de término (por ej. miércoles).
    3. Conociendo su día de inicio, filtramos daysArray para recuperar el elemento de la lista (día) que coincide con dicho día. Durante este test, ignoramos la posible presencia del carácter "½". A continuación, hacemos unos cuantos cálculos para descubrir el valor de la propiedad left de la tarea correspondiente.
    4. Conociendo su día de finalización, filtramos daysArray para recuperar el elemento de lista (día) que coincida con este día. Durante esta prueba, ignoramos la posible presencia del carácter "½". Después, hacemos unos cuantos cálculos para determinar el valor de la propiedad width de la tarea relacionada.   
    1
    tasks.forEach(el => {
    
    2
        // 1
    
    
    3
        const duration = el.dataset.duration.split("-");
    
    4
        // 2
    
    
    5
        const startDay = duration[0];
    
    6
        const endDay = duration[1];
    
    7
        let left = 0,
    
    8
          width = 0;
    
    9
    10
        // 3
    
    
    11
        if (startDay.endsWith("½")) {
    
    12
          const filteredArray = daysArray.filter(day => day.textContent == startDay.slice(0, -1));
    
    13
          left = filteredArray[0].offsetLeft + filteredArray[0].offsetWidth / 2;
    
    14
        } else {
    
    15
          const filteredArray = daysArray.filter(day => day.textContent == startDay);
    
    16
          left = filteredArray[0].offsetLeft;
    
    17
        }
    
    18
        
    
    19
        // 4
    
    
    20
        if (endDay.endsWith("½")) {
    
    21
          const filteredArray = daysArray.filter(day => day.textContent == endDay.slice(0, -1));
    
    22
          width = filteredArray[0].offsetLeft + filteredArray[0].offsetWidth / 2 - left;
    
    23
        } else {
    
    24
          const filteredArray = daysArray.filter(day => day.textContent == endDay);
    
    25
          width = filteredArray[0].offsetLeft + filteredArray[0].offsetWidth - left;
    
    26
        }
    
    27
        ...
    
    28
      });
    

    Nota: En el anterior código, usamos la propiedad Element.offsetLeft para recuperar la posición izquierda de un elemento relativa a su elemento padre. Además, aprovechamos la propiedad Element.offsetWidth para encontrar la anchura del elemento. Como otra opción para determinar su anchura, podríamos haber usado igualmente el método más preciso Element.getBoundingClientRect().

    Establecer los estilos

    Habiendo calculado los valores left y width de cada tarea de la plantilla del diagrama de Gantt, el último paso consiste en realizar las siguientes acciones:

    1. Aplicar los correspondientes estilos.
    2. Coger el valor del atributo data-color y establecerlo como el color de fondo de la tarea.
    3. Mostrar la tarea. Recuerda que todas las tareas están en principio ocultas.
    4. Las acciones 2 y 3 deberían ejecutarse solo cuando se cargue la página, ya que sus valores no cambiarán cada vez que se redimensione la ventana del navegador.
    1
    tasks.forEach(el => {
    
    2
      ...  
    
    3
      // 1
    
    
    4
      el.style.left = `${left}px`;
    
    5
      el.style.width = `${width}px`;
    
    6
      // 4
    
    
    7
      if (e.type == "load") {
    
    8
        // 2
    
    
    9
        el.style.backgroundColor = el.dataset.color;
    
    10
        // 3
    
    
    11
        el.style.opacity = 1;
    
    12
      }
    
    13
     });
    

    Conclusión

    ¡Eso es todo! Hemos creado una plantilla de Gantt con JavaScript y CSS totalmente funcional. Gracias por seguir todo el tutorial sobre cómo hacer un diagrama de Gantt, esperamos que te haya resultado un buen ejercicio con el que refrescar tus conocimientos sobre JavaScript. Aquí tienes un ejemplo de la demostración final:  

    Please accept marketing cookies to load this content.

    Juega con ella y si encuentras cualquier forma de mejorar su funcionalidad, ¡compártela! Mantente conectado o conectada para descubrir el equivalente diagrama de Gantt sin JavaScript, solo con CSS.

    Como siempre, ¡Gracias por leerme!

    Pasos siguientes

    Si quieres retarte a ti mismo o misma, prueba a convertir esta línea del tiempo vertical en un diagrama de Gantt.

    Continúa leyendo

    Hojas de cálculo, visualización de datos, plantillas de diagramas de Gantt, gráficos, animaciones, ¡existe mucho más por descubrir!