Data
GanttTimeline
Gantt generico con righe (opzionalmente raggruppate) e barre posizionate su un asse temporale o lineare continuo, con tacche, colori per stato e indicatore "adesso" configurabili.
Import
import { GanttTimeline } from '@pzeta/vue-components'
Esempio Base
Props
| Prop | Tipo | Default | Descrizione |
|---|---|---|---|
rows | GanttRow[] | (required) | Elenco delle righe da renderizzare; ogni riga ha un'etichetta e una o piu' barre |
domainStart | GanttValue | (required) | Inizio del dominio dell'asse (ISO datetime/date per scala time, numero per scala linear) |
domainEnd | GanttValue | (required) | Fine del dominio dell'asse |
scale | 'time' | 'linear' | 'time' | Interpretazione dei valori: time (datetime convertito in epoch) o linear (numerico) |
ticks | number | GanttTick[] | 12 | Numero di tacche equidistanti oppure elenco esplicito di tacche con posizione/label |
tickFormat | (value: number) => string | undefined | Formattatore dell'etichetta della tacca; riceve il valore numerico del dominio |
coloriPerStato | Record<string, string> | {} | Mappa stato => colore CSS, usata quando la barra non ha color esplicito |
raggruppaPer | string | undefined | Nome del campo della riga su cui raggruppare; renderizza intestazioni di gruppo |
showNowIndicator | boolean | false | Mostra la linea verticale rossa dell'ora/data corrente (solo scala time) |
rowLabelWidth | string | '11rem' | Larghezza (CSS) della colonna etichette riga |
rowHeight | string | '2rem' | Altezza (CSS) di ogni riga/barra |
minChartWidth | string | '640px' | Larghezza minima dell'area grafico; oltre questa soglia scatta lo scroll orizzontale |
locale | string | 'it-IT' | Locale Intl.DateTimeFormat per la formattazione di default delle tacche temporali |
emptyText | string | 'Nessun dato da mostrare' | Testo mostrato quando rows e' vuoto |
GanttRow
| Proprieta' | Tipo | Descrizione |
|---|---|---|
id | string | number | Identificatore univoco della riga |
label | string | Etichetta mostrata nella colonna di sinistra |
bars | GanttBar[] | Barre posizionate sulla track della riga |
gruppo | string | Chiave di raggruppamento (usata se raggruppaPer e' valorizzato) |
[key] | unknown | Qualsiasi altro campo: disponibile nello slot #rowLabel e per il raggruppamento |
GanttBar
| Proprieta' | Tipo | Descrizione |
|---|---|---|
id | string | number | Identificatore opzionale (fallback all'indice come key) |
start | GanttValue | Inizio della barra |
end | GanttValue | null | Fine della barra; null = ancora in corso (estesa fino ad "adesso" su scala time, alla fine del dominio su scala linear) |
stato | string | Chiave di stato usata per risolvere il colore via coloriPerStato |
color | string | Colore CSS esplicito; ha precedenza su coloriPerStato |
label | string | Etichetta opzionale mostrata dentro la barra |
[key] | unknown | Qualsiasi altro campo: disponibile nello slot #bar |
GanttTick
| Proprieta' | Tipo | Descrizione |
|---|---|---|
position | number | Posizione frazionaria sull'asse, da 0 a 1 |
label | string | Etichetta della tacca |
Slots
| Slot | Props | Descrizione |
|---|---|---|
cornerHeader | - | Contenuto dell'angolo in alto a sinistra (sopra la colonna etichette) |
groupHeader | { label: string } | Override dell'intestazione di un gruppo (quando raggruppaPer e' attivo) |
rowLabel | { row: GanttRow } | Rendering custom dell'etichetta riga nella colonna fissa di sinistra |
bar | { bar: GanttBar, row: GanttRow } | Contenuto custom all'interno di una barra |
empty | - | Override del messaggio mostrato quando rows e' vuoto |
Emits
| Evento | Payload | Descrizione |
|---|---|---|
select | { row: GanttRow, bar: GanttBar, originalEvent: MouseEvent } | Emesso al click su una barra |
Esempi
Asse mensile con righe raggruppate
Asse a giorni del mese, righe raggruppate per reparto tramite raggruppaPer, una barra per valutazione colorata per stato. Il click su una barra emette select.
Scala lineare con slot custom
Con scale="linear" i valori sono interpretati come numeri puri (es. percentuali, quantita'). Gli slot #rowLabel e #bar permettono di personalizzare etichette e contenuto delle barre.
<script setup>
const rows = [
{ id: 1, label: 'Fase analisi', bars: [{ start: 0, end: 40, color: '#3b82f6', label: '40%' }] },
{ id: 2, label: 'Fase sviluppo', bars: [{ start: 20, end: 90, color: '#22c55e', label: '70%' }] },
{ id: 3, label: 'Fase rilascio', bars: [{ start: 80, end: 100, color: '#f59e0b', label: '20%' }] },
]
const tickPercento = (value) => `${Math.round(value)}%`
</script>
<template>
<GanttTimeline
:rows="rows"
scale="linear"
:domain-start="0"
:domain-end="100"
:ticks="5"
:tick-format="tickPercento"
>
<template #rowLabel="{ row }">
<span class="font-semibold text-gray-700">{{ row.label }}</span>
</template>
<template #bar="{ bar }">
<span class="truncate">{{ bar.label }}</span>
</template>
</GanttTimeline>
</template>
Note Comportamento
- I valori (
start,end,domainStart,domainEnd) sono convertiti in numero: su scalatimetramitenew Date(value).getTime(), su scalalineartramiteNumber(value); i valori non parsabili diventano0 - Una barra con
end: nulle' considerata "in corso": su scalatimeviene estesa fino al minimo tra "adesso" e fine dominio, su scalalinearfino alla fine del dominio - Le barre vengono ritagliate (clamp) ai limiti del dominio; una barra completamente fuori dominio o di larghezza nulla non viene renderizzata
- Il colore di una barra si risolve nell'ordine:
coloresplicito, poicoloriPerStato[stato], infine il grigio di default#9ca3af - Con
raggruppaPerle righe sono ordinate per ordine di prima apparizione del gruppo e rese contigue sotto l'intestazione del rispettivo gruppo - L'indicatore "adesso" (
showNowIndicator) e' attivo solo su scalatimee si aggiorna ogni 60 secondi; viene mostrato solo se il momento corrente cade dentro il dominio - Il contenitore ha
overflow-x: autoe l'area grafico unamin-widthpari aminChartWidth: su viewport stretti compare lo scroll orizzontale
Accessibilita'
- Ogni barra e' un
<button type="button">nativo, quindi raggiungibile da tastiera con anello di focus (focus:ring-2) - Le etichette delle barre lunghe vengono troncate; per casi complessi valutare uno slot
#barcon contenuto descrittivo
TypeScript
import type {
GanttTimelineProps,
GanttRow,
GanttBar,
GanttBarSelectPayload,
} from '@pzeta/vue-components'
interface SessioneRow extends GanttRow {
idDipendente: number
}
interface SessioneBar extends GanttBar {
stato: 'completa' | 'attiva' | 'errore'
}
const onSelect = (payload: GanttBarSelectPayload) => {
const bar = payload.bar as SessioneBar
console.log('riga', payload.row.label, 'stato', bar.stato)
}
Quando usarlo
- Timeline orarie intraday (es. presenze, sessioni di lavoro) con indicatore dell'ora corrente
- Timeline a giorni/mesi (es. valutazioni, attivita' pianificate) con righe raggruppate per reparto/categoria
- Avanzamento su scala lineare/numerica (es. percentuali, range continui) con
scale="linear"
Per casi diversi:
- Griglia risorsa x giorno della settimana (planner/turni) → WeekScheduler
- Cronologia di eventi singola, non gridata per riga → Timeline
- Vista mese con eventi del giorno → EventCalendar