Cómo hacer un diagrama de Gantt con JavaScript y CSS
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:
¿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


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.




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-durationy el atributodata-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 atributodata-durationdebería estar indicado en el formato[startDay]½-[endDay]½. Así que por ejemplo usaremosdata-duration="tue-wed½"para una tarea que tenga que empezar el martes y terminar el miércoles al mediodía. De igual maneradata-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 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:
- Cogemos los elementos de los dos listados.
- Convertimos la NodeList
daysen una cadena real usando el operador spread (operador de propagación). Alternativamente, podríamos haber usado el métodoArray.from(). Esta conversión nos permitirá beneficiarnos del métodofilter(), el cual está disponible en cadenas, para filtrar los días. - 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:
- Cogemos el valor de su atributo
data-duration(por ej. martes-miércoles). Además, separamos este valor usando un "-" como separador. - 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).
- Conociendo su día de inicio, filtramos
daysArraypara 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 propiedadleftde la tarea correspondiente. - Conociendo su día de finalización, filtramos
daysArraypara 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 propiedadwidthde 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:
- Aplicar los correspondientes estilos.
- Coger el valor del atributo
data-colory establecerlo como el color de fondo de la tarea. - Mostrar la tarea. Recuerda que todas las tareas están en principio ocultas.
- 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:
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!


Cómo Hacer un Diagrama de Flujo y de Gantt en Keynote con Plantillas

Andrew Childress26 Oct 2020

Cómo Hacer un Diagrama de Gantt en Excel

Bob Flisser09 Mar 2016

Cómo crear el gráfico animado de un termómetro con CSS

George Martsoukos19 Jun 2019

Crea un portafolio estático con un gráfico de barras avanzado en CSS

George Martsoukos11 Jun 2019



