Gantt Baselines
A baseline is a saved snapshot of task dates and progress at a specific point in time (e.g. when the project was approved). The Gantt chart can overlay these baseline bars beneath the live bars, making schedule drift immediately visible.
Source code
---import '@revolist/gantt/styles.css';import GanttBaseline from '@revolist/revogrid-examples/components/gantt/GanttBaseline.vue';---
<GanttBaseline client:only="vue" />import { createDropdownControl } from '@revolist/ui/dropdown/control';import { createControl } from '@revolist/ui';import { defineCustomElements } from '@revolist/revogrid/loader';defineCustomElements();
import { GanttPlugin, createDefaultTaskTableColumn } from '@revolist/gantt';import type { GanttTaskSourceRow, DependencyEntity, BaselineSnapshot,} from '@revolist/gantt';type CalendarEntity = NonNullable< import('@revolist/gantt').GanttPluginConfig['calendars']>[number];import { currentTheme } from '../composables/useRandomData';
const { isDark } = currentTheme();
const PROJECT_ID = 'project-web-redesign';const CALENDAR_ID = 'cal-standard';
const ganttConfig = { id: PROJECT_ID, name: 'Website Redesign', version: '1', currency: 'USD', timeZone: 'UTC', primaryCalendarId: CALENDAR_ID, updatedAt: '2026-04-06T00:00:00Z', statusDate: '2026-04-06', zoomPreset: 'week-month' as const, visuals: { showBaseline: true, baselineId: 'baseline-approved', },};
const baselineColumnProps = [ 'wbs', 'name', 'startDate', 'endDate', 'startVarianceDays', 'finishVarianceDays', 'durationVariance', 'progressVariancePercent',] as const;
const calendars: CalendarEntity[] = [ { id: CALENDAR_ID, name: 'Standard', timeZone: 'UTC', workingDays: [1, 2, 3, 4, 5], holidays: [], hoursPerDay: 8, },];
// Current (live) tasks — note Design slipped by 3 days vs baselineconst tasks: GanttTaskSourceRow[] = [ { id: 't1', parentId: null, name: 'Design', type: 'summary', workflowStatus: 'in-progress', startDate: '2026-04-06', endDate: '2026-04-27', duration: 18, percentDone: 50, calendarId: CALENDAR_ID, tags: [], }, { id: 't2', parentId: 't1', name: 'Wireframes', type: 'task', workflowStatus: 'done', startDate: '2026-04-06', endDate: '2026-04-10', duration: 5, percentDone: 100, calendarId: CALENDAR_ID, tags: [], }, { id: 't3', parentId: 't1', name: 'Design Review', type: 'milestone', workflowStatus: 'done', startDate: '2026-04-10', endDate: '2026-04-10', duration: 0, percentDone: 100, calendarId: CALENDAR_ID, tags: ['milestone'], }, { id: 't4', parentId: 't1', name: 'Visual Design', type: 'task', workflowStatus: 'in-progress', startDate: '2026-04-13', endDate: '2026-04-27', duration: 13, // slipped from 10 → 13 percentDone: 30, calendarId: CALENDAR_ID, tags: [], }, { id: 't5', parentId: null, name: 'Development', type: 'summary', workflowStatus: 'not-started', startDate: '2026-04-28', endDate: '2026-05-21', duration: 18, percentDone: 0, calendarId: CALENDAR_ID, tags: [], }, { id: 't6', parentId: 't5', name: 'Frontend', type: 'task', workflowStatus: 'not-started', startDate: '2026-04-28', endDate: '2026-05-14', duration: 13, percentDone: 0, calendarId: CALENDAR_ID, tags: [], }, { id: 't7', parentId: 't5', name: 'Backend', type: 'task', workflowStatus: 'not-started', startDate: '2026-04-28', endDate: '2026-05-21', duration: 18, percentDone: 0, calendarId: CALENDAR_ID, tags: [], }, { id: 't8', parentId: null, name: 'Launch', type: 'milestone', workflowStatus: 'not-started', startDate: '2026-05-21', endDate: '2026-05-21', duration: 0, percentDone: 0, calendarId: CALENDAR_ID, tags: ['milestone'], },];
const dependencies: DependencyEntity[] = [ { id: 'd1', predecessorTaskId: 't2', successorTaskId: 't3', type: 'finish-to-start', lagDays: 0, }, { id: 'd2', predecessorTaskId: 't3', successorTaskId: 't4', type: 'finish-to-start', lagDays: 1, }, { id: 'd3', predecessorTaskId: 't4', successorTaskId: 't6', type: 'finish-to-start', lagDays: 1, }, { id: 'd4', predecessorTaskId: 't4', successorTaskId: 't7', type: 'finish-to-start', lagDays: 1, }, { id: 'd5', predecessorTaskId: 't6', successorTaskId: 't8', type: 'finish-to-start', lagDays: 0, }, { id: 'd6', predecessorTaskId: 't7', successorTaskId: 't8', type: 'finish-to-start', lagDays: 0, },];
// Baseline — the original approved plan before Visual Design slippedconst baselines: BaselineSnapshot[] = [ { id: 'baseline-approved', name: 'Approved Plan', capturedAt: '2026-04-01T08:00:00Z', tasks: [ { taskId: 't1', startDate: '2026-04-06', endDate: '2026-04-24', duration: 120, progressPercent: 0, }, { taskId: 't2', startDate: '2026-04-06', endDate: '2026-04-10', duration: 40, progressPercent: 0, }, { taskId: 't3', startDate: '2026-04-10', endDate: '2026-04-10', duration: 0, progressPercent: 0, }, { taskId: 't4', startDate: '2026-04-13', endDate: '2026-04-24', duration: 80, progressPercent: 0, }, { taskId: 't5', startDate: '2026-04-27', endDate: '2026-05-20', duration: 144, progressPercent: 0, }, { taskId: 't6', startDate: '2026-04-27', endDate: '2026-05-13', duration: 104, progressPercent: 0, }, { taskId: 't7', startDate: '2026-04-27', endDate: '2026-05-20', duration: 144, progressPercent: 0, }, { taskId: 't8', startDate: '2026-05-20', endDate: '2026-05-20', duration: 0, progressPercent: 0, }, ], }, { id: 'baseline-replan', name: 'Replan After Design Slip', capturedAt: '2026-04-15T08:00:00Z', tasks: [ { taskId: 't1', startDate: '2026-04-06', endDate: '2026-04-27', duration: 144, progressPercent: 25, }, { taskId: 't2', startDate: '2026-04-06', endDate: '2026-04-10', duration: 40, progressPercent: 100, }, { taskId: 't3', startDate: '2026-04-10', endDate: '2026-04-10', duration: 0, progressPercent: 100, }, { taskId: 't4', startDate: '2026-04-13', endDate: '2026-04-25', duration: 104, progressPercent: 20, }, { taskId: 't5', startDate: '2026-04-28', endDate: '2026-05-21', duration: 144, progressPercent: 0, }, { taskId: 't6', startDate: '2026-04-28', endDate: '2026-05-14', duration: 104, progressPercent: 0, }, { taskId: 't7', startDate: '2026-04-28', endDate: '2026-05-21', duration: 144, progressPercent: 0, }, { taskId: 't8', startDate: '2026-05-21', endDate: '2026-05-21', duration: 0, progressPercent: 0, }, ], },];
export function load(parentSelector: string) { const container = document.createElement('div'); container.className = 'gantt-example-container';
const toolbar = document.createElement('div'); toolbar.className = 'gantt-toolbar'; Object.assign(toolbar.style, { marginBottom: '1rem', display: 'flex', gap: '1rem', alignItems: 'center', });
const label = document.createElement('label'); Object.assign(label.style, { display: 'flex', alignItems: 'center', gap: '0.5rem', cursor: 'pointer', });
const checkbox = createControl(document, 'input', { type: 'checkbox' }); checkbox.type = 'checkbox'; checkbox.checked = ganttConfig.visuals.showBaseline;
label.appendChild(checkbox); label.appendChild(document.createTextNode('Show Baseline')); toolbar.appendChild(label);
const selectLabel = document.createElement('label'); Object.assign(selectLabel.style, { display: 'flex', alignItems: 'center', gap: '0.5rem', }); const select = createDropdownControl(document, { source: baselines.map((item) => ({ value: item.id, label: item.name })), config: { ariaLabel: 'Baseline' }, }); select.value = ganttConfig.visuals.baselineId; selectLabel.appendChild(document.createTextNode('Baseline')); selectLabel.appendChild(select.element); toolbar.appendChild(selectLabel); container.appendChild(toolbar);
const grid = document.createElement('revo-grid'); grid.theme = isDark() ? 'darkCompact' : 'compact'; grid.hideAttribution = true; grid.plugins = [GanttPlugin]; grid.gantt = ganttConfig; grid.ganttCalendars = calendars; grid.ganttDependencies = dependencies; grid.ganttBaselines = baselines; grid.source = tasks; grid.columns = baselineColumnProps.map((prop) => createDefaultTaskTableColumn(prop), );
container.appendChild(grid); document.querySelector(parentSelector)?.appendChild(container);
checkbox.addEventListener('change', (e) => { const showBaseline = (e.target as HTMLInputElement).checked; grid.gantt = { ...grid.gantt, visuals: { ...grid.gantt.visuals, showBaseline, }, }; });
select.onChange = (value) => { grid.gantt = { ...grid.gantt, visuals: { ...grid.gantt.visuals, baselineId: value, }, }; }; return () => { select.destroy(); grid.remove(); container.remove(); };}<template> <div class="gantt-example-container"> <div class="gantt-toolbar" :style="{ marginBottom: '1rem', display: 'flex', gap: '1rem', alignItems: 'center', }" > <label :style="{ display: 'flex', alignItems: 'center', gap: '0.5rem', cursor: 'pointer', }" > <input v-rv-control type="checkbox" v-model="showBaseline" /> Show Baseline </label> <label :style="{ display: 'flex', alignItems: 'center', gap: '0.5rem' }"> Baseline <Dropdown class="rv-select" v-model="baselineId" :source=" baselines.map((item) => ({ value: item.id, label: item.name })) " :config="{ ariaLabel: 'Baseline' }" /> </label> </div> <RevoGrid hide-attribution style="height: 500px" :theme="isDark ? 'darkCompact' : 'compact'" :plugins="plugins" :source="tasks" :columns="columns" :gantt.prop="ganttConfig" :gantt-dependencies.prop="dependencies" :gantt-calendars.prop="calendars" :gantt-baselines.prop="baselines" /> </div></template>
<script setup lang="ts">import { Dropdown } from '@revolist/ui/vue';import { vRvControl } from '@revolist/ui/vue-control';import { ref, computed } from 'vue';import RevoGrid from '@revolist/vue3-datagrid';import { GanttPlugin, createDefaultTaskTableColumn } from '@revolist/gantt';import type { GanttTaskSourceRow, DependencyEntity, BaselineSnapshot,} from '@revolist/gantt';type CalendarEntity = NonNullable< import('@revolist/gantt').GanttPluginConfig['calendars']>[number];import { currentThemeVue } from '../composables/useRandomData';
const { isDark } = currentThemeVue();
const PROJECT_ID = 'project-web-redesign';const CALENDAR_ID = 'cal-standard';
const plugins = ref([GanttPlugin]);const showBaseline = ref(true);const baselineId = ref('baseline-approved');
const ganttConfig = computed(() => ({ id: PROJECT_ID, name: 'Website Redesign', version: '1', currency: 'USD', timeZone: 'UTC', primaryCalendarId: CALENDAR_ID, updatedAt: '2026-04-06T00:00:00Z', statusDate: '2026-04-06', zoomPreset: 'week-month' as const, visuals: { showBaseline: showBaseline.value, baselineId: baselineId.value, },}));
const calendars = ref<CalendarEntity[]>([ { id: CALENDAR_ID, name: 'Standard', timeZone: 'UTC', workingDays: [1, 2, 3, 4, 5], holidays: [], hoursPerDay: 8, },]);
const tasks = ref<GanttTaskSourceRow[]>([ { id: 't1', parentId: null, name: 'Design', type: 'summary', workflowStatus: 'in-progress', startDate: '2026-04-06', endDate: '2026-04-27', duration: 18, percentDone: 50, calendarId: CALENDAR_ID, tags: [], }, { id: 't2', parentId: 't1', name: 'Wireframes', type: 'task', workflowStatus: 'done', startDate: '2026-04-06', endDate: '2026-04-10', duration: 5, percentDone: 100, calendarId: CALENDAR_ID, tags: [], }, { id: 't3', parentId: 't1', name: 'Design Review', type: 'milestone', workflowStatus: 'done', startDate: '2026-04-10', endDate: '2026-04-10', duration: 0, percentDone: 100, calendarId: CALENDAR_ID, tags: ['milestone'], }, { id: 't4', parentId: 't1', name: 'Visual Design', type: 'task', workflowStatus: 'in-progress', startDate: '2026-04-13', endDate: '2026-04-27', duration: 13, percentDone: 30, calendarId: CALENDAR_ID, tags: [], }, { id: 't5', parentId: null, name: 'Development', type: 'summary', workflowStatus: 'not-started', startDate: '2026-04-28', endDate: '2026-05-21', duration: 18, percentDone: 0, calendarId: CALENDAR_ID, tags: [], }, { id: 't6', parentId: 't5', name: 'Frontend', type: 'task', workflowStatus: 'not-started', startDate: '2026-04-28', endDate: '2026-05-14', duration: 13, percentDone: 0, calendarId: CALENDAR_ID, tags: [], }, { id: 't7', parentId: 't5', name: 'Backend', type: 'task', workflowStatus: 'not-started', startDate: '2026-04-28', endDate: '2026-05-21', duration: 18, percentDone: 0, calendarId: CALENDAR_ID, tags: [], }, { id: 't8', parentId: null, name: 'Launch', type: 'milestone', workflowStatus: 'not-started', startDate: '2026-05-21', endDate: '2026-05-21', duration: 0, percentDone: 0, calendarId: CALENDAR_ID, tags: ['milestone'], },]);
const dependencies = ref<DependencyEntity[]>([ { id: 'd1', predecessorTaskId: 't2', successorTaskId: 't3', type: 'finish-to-start', lagDays: 0, }, { id: 'd2', predecessorTaskId: 't3', successorTaskId: 't4', type: 'finish-to-start', lagDays: 1, }, { id: 'd3', predecessorTaskId: 't4', successorTaskId: 't6', type: 'finish-to-start', lagDays: 1, }, { id: 'd4', predecessorTaskId: 't4', successorTaskId: 't7', type: 'finish-to-start', lagDays: 1, }, { id: 'd5', predecessorTaskId: 't6', successorTaskId: 't8', type: 'finish-to-start', lagDays: 0, }, { id: 'd6', predecessorTaskId: 't7', successorTaskId: 't8', type: 'finish-to-start', lagDays: 0, },]);
const baselines = ref<BaselineSnapshot[]>([ { id: 'baseline-approved', name: 'Approved Plan', capturedAt: '2026-04-01T08:00:00Z', tasks: [ { taskId: 't1', startDate: '2026-04-06', endDate: '2026-04-24', duration: 120, progressPercent: 0, }, { taskId: 't2', startDate: '2026-04-06', endDate: '2026-04-10', duration: 40, progressPercent: 0, }, { taskId: 't3', startDate: '2026-04-10', endDate: '2026-04-10', duration: 0, progressPercent: 0, }, { taskId: 't4', startDate: '2026-04-13', endDate: '2026-04-24', duration: 80, progressPercent: 0, }, { taskId: 't5', startDate: '2026-04-27', endDate: '2026-05-20', duration: 144, progressPercent: 0, }, { taskId: 't6', startDate: '2026-04-27', endDate: '2026-05-13', duration: 104, progressPercent: 0, }, { taskId: 't7', startDate: '2026-04-27', endDate: '2026-05-20', duration: 144, progressPercent: 0, }, { taskId: 't8', startDate: '2026-05-20', endDate: '2026-05-20', duration: 0, progressPercent: 0, }, ], }, { id: 'baseline-replan', name: 'Replan After Design Slip', capturedAt: '2026-04-15T08:00:00Z', tasks: [ { taskId: 't1', startDate: '2026-04-06', endDate: '2026-04-27', duration: 144, progressPercent: 25, }, { taskId: 't2', startDate: '2026-04-06', endDate: '2026-04-10', duration: 40, progressPercent: 100, }, { taskId: 't3', startDate: '2026-04-10', endDate: '2026-04-10', duration: 0, progressPercent: 100, }, { taskId: 't4', startDate: '2026-04-13', endDate: '2026-04-25', duration: 104, progressPercent: 20, }, { taskId: 't5', startDate: '2026-04-28', endDate: '2026-05-21', duration: 144, progressPercent: 0, }, { taskId: 't6', startDate: '2026-04-28', endDate: '2026-05-14', duration: 104, progressPercent: 0, }, { taskId: 't7', startDate: '2026-04-28', endDate: '2026-05-21', duration: 144, progressPercent: 0, }, { taskId: 't8', startDate: '2026-05-21', endDate: '2026-05-21', duration: 0, progressPercent: 0, }, ], },]);
const baselineColumnProps = [ 'wbs', 'name', 'startDate', 'endDate', 'startVarianceDays', 'finishVarianceDays', 'durationVariance', 'progressVariancePercent',] as const;
const columns = ref( baselineColumnProps.map((prop) => createDefaultTaskTableColumn(prop)),);</script>import { Input as UiInput } from '@revolist/ui/react-control';import { Dropdown as UiDropdown } from '@revolist/ui/react';import React, { useMemo } from 'react';import { RevoGrid } from '@revolist/react-datagrid';import { GanttPlugin, createDefaultTaskTableColumn } from '@revolist/gantt';import type { GanttTaskSourceRow, DependencyEntity, BaselineSnapshot,} from '@revolist/gantt';type CalendarEntity = NonNullable< import('@revolist/gantt').GanttPluginConfig['calendars']>[number];import { currentTheme } from '../composables/useRandomData';
const { isDark } = currentTheme();
const PROJECT_ID = 'project-web-redesign';const CALENDAR_ID = 'cal-standard';const baselineColumnProps = [ 'wbs', 'name', 'startDate', 'endDate', 'startVarianceDays', 'finishVarianceDays', 'durationVariance', 'progressVariancePercent',] as const;
const tasks: GanttTaskSourceRow[] = [ { id: 't1', parentId: null, name: 'Design', type: 'summary', workflowStatus: 'in-progress', startDate: '2026-04-06', endDate: '2026-04-27', duration: 18, percentDone: 50, calendarId: CALENDAR_ID, tags: [], }, { id: 't2', parentId: 't1', name: 'Wireframes', type: 'task', workflowStatus: 'done', startDate: '2026-04-06', endDate: '2026-04-10', duration: 5, percentDone: 100, calendarId: CALENDAR_ID, tags: [], }, { id: 't3', parentId: 't1', name: 'Design Review', type: 'milestone', workflowStatus: 'done', startDate: '2026-04-10', endDate: '2026-04-10', duration: 0, percentDone: 100, calendarId: CALENDAR_ID, tags: ['milestone'], }, { id: 't4', parentId: 't1', name: 'Visual Design', type: 'task', workflowStatus: 'in-progress', startDate: '2026-04-13', endDate: '2026-04-27', duration: 13, // slipped percentDone: 30, calendarId: CALENDAR_ID, tags: [], }, { id: 't5', parentId: null, name: 'Development', type: 'summary', workflowStatus: 'not-started', startDate: '2026-04-28', endDate: '2026-05-21', duration: 18, percentDone: 0, calendarId: CALENDAR_ID, tags: [], }, { id: 't6', parentId: 't5', name: 'Frontend', type: 'task', workflowStatus: 'not-started', startDate: '2026-04-28', endDate: '2026-05-14', duration: 13, percentDone: 0, calendarId: CALENDAR_ID, tags: [], }, { id: 't7', parentId: 't5', name: 'Backend', type: 'task', workflowStatus: 'not-started', startDate: '2026-04-28', endDate: '2026-05-21', duration: 18, percentDone: 0, calendarId: CALENDAR_ID, tags: [], }, { id: 't8', parentId: null, name: 'Launch', type: 'milestone', workflowStatus: 'not-started', startDate: '2026-05-21', endDate: '2026-05-21', duration: 0, percentDone: 0, calendarId: CALENDAR_ID, tags: ['milestone'], },];
const dependencies: DependencyEntity[] = [ { id: 'd1', predecessorTaskId: 't2', successorTaskId: 't3', type: 'finish-to-start', lagDays: 0, }, { id: 'd2', predecessorTaskId: 't3', successorTaskId: 't4', type: 'finish-to-start', lagDays: 1, }, { id: 'd3', predecessorTaskId: 't4', successorTaskId: 't6', type: 'finish-to-start', lagDays: 1, }, { id: 'd4', predecessorTaskId: 't4', successorTaskId: 't7', type: 'finish-to-start', lagDays: 1, }, { id: 'd5', predecessorTaskId: 't6', successorTaskId: 't8', type: 'finish-to-start', lagDays: 0, }, { id: 'd6', predecessorTaskId: 't7', successorTaskId: 't8', type: 'finish-to-start', lagDays: 0, },];
const calendars: CalendarEntity[] = [ { id: CALENDAR_ID, name: 'Standard', timeZone: 'UTC', workingDays: [1, 2, 3, 4, 5], holidays: [], hoursPerDay: 8, },];
const baselines: BaselineSnapshot[] = [ { id: 'baseline-approved', name: 'Approved Plan', capturedAt: '2026-04-01T08:00:00Z', tasks: [ { taskId: 't1', startDate: '2026-04-06', endDate: '2026-04-24', duration: 120, progressPercent: 0, }, { taskId: 't2', startDate: '2026-04-06', endDate: '2026-04-10', duration: 40, progressPercent: 0, }, { taskId: 't3', startDate: '2026-04-10', endDate: '2026-04-10', duration: 0, progressPercent: 0, }, { taskId: 't4', startDate: '2026-04-13', endDate: '2026-04-24', duration: 80, progressPercent: 0, }, { taskId: 't5', startDate: '2026-04-27', endDate: '2026-05-20', duration: 144, progressPercent: 0, }, { taskId: 't6', startDate: '2026-04-27', endDate: '2026-05-13', duration: 104, progressPercent: 0, }, { taskId: 't7', startDate: '2026-04-27', endDate: '2026-05-20', duration: 144, progressPercent: 0, }, { taskId: 't8', startDate: '2026-05-20', endDate: '2026-05-20', duration: 0, progressPercent: 0, }, ], }, { id: 'baseline-replan', name: 'Replan After Design Slip', capturedAt: '2026-04-15T08:00:00Z', tasks: [ { taskId: 't1', startDate: '2026-04-06', endDate: '2026-04-27', duration: 144, progressPercent: 25, }, { taskId: 't2', startDate: '2026-04-06', endDate: '2026-04-10', duration: 40, progressPercent: 100, }, { taskId: 't3', startDate: '2026-04-10', endDate: '2026-04-10', duration: 0, progressPercent: 100, }, { taskId: 't4', startDate: '2026-04-13', endDate: '2026-04-25', duration: 104, progressPercent: 20, }, { taskId: 't5', startDate: '2026-04-28', endDate: '2026-05-21', duration: 144, progressPercent: 0, }, { taskId: 't6', startDate: '2026-04-28', endDate: '2026-05-14', duration: 104, progressPercent: 0, }, { taskId: 't7', startDate: '2026-04-28', endDate: '2026-05-21', duration: 144, progressPercent: 0, }, { taskId: 't8', startDate: '2026-05-21', endDate: '2026-05-21', duration: 0, progressPercent: 0, }, ], },];
function GanttBaseline() { const [showBaseline, setShowBaseline] = React.useState(true); const [baselineId, setBaselineId] = React.useState('baseline-approved'); const ganttConfig = useMemo( () => ({ id: PROJECT_ID, name: 'Website Redesign', version: '1', currency: 'USD', timeZone: 'UTC', primaryCalendarId: CALENDAR_ID, updatedAt: '2026-04-06T00:00:00Z', statusDate: '2026-04-06', zoomPreset: 'week-month' as const, visuals: { showBaseline, baselineId }, }), [baselineId, showBaseline], );
const columns = useMemo( () => baselineColumnProps.map((prop) => createDefaultTaskTableColumn(prop)), [], );
return ( <div className="gantt-example-container"> <div className="gantt-toolbar" style={{ marginBottom: '1rem', display: 'flex', gap: '1rem', alignItems: 'center', }} > <label style={{ display: 'flex', alignItems: 'center', gap: '0.5rem', cursor: 'pointer', }} > <UiInput type="checkbox" checked={showBaseline} onChange={(e) => setShowBaseline(e.target.checked)} /> Show Baseline </label> <label style={{ display: 'flex', alignItems: 'center', gap: '0.5rem' }}> Baseline <UiDropdown value={baselineId} onChange={(nextValue) => setBaselineId(String(nextValue))} source={baselines.map((baseline) => ({ value: baseline.id, label: baseline.name, }))} config={{ nativeTabNavigation: true, topLayer: true, ariaLabel: 'Baseline', }} /> </label> </div> <RevoGrid style={{ height: '500px' }} theme={isDark() ? 'darkCompact' : 'compact'} hideAttribution plugins={[GanttPlugin]} source={tasks} columns={columns} gantt={ganttConfig} ganttDependencies={dependencies} ganttCalendars={calendars} ganttBaselines={baselines} /> </div> );}
export default GanttBaseline;import { UiComponent } from '@revolist/ui/angular';import { UiControlDirective } from '@revolist/ui/angular-control';import { Component, NO_ERRORS_SCHEMA, ViewEncapsulation } from '@angular/core';import { CommonModule } from '@angular/common';import { RevoGrid } from '@revolist/angular-datagrid';import { GanttPlugin, createDefaultTaskTableColumn } from '@revolist/gantt';import type { GanttTaskSourceRow, DependencyEntity, BaselineSnapshot,} from '@revolist/gantt';type CalendarEntity = NonNullable< import('@revolist/gantt').GanttPluginConfig['calendars']>[number];import { currentTheme } from '../composables/useRandomData';
const PROJECT_ID = 'project-web-redesign';const CALENDAR_ID = 'cal-standard';
@Component({ selector: 'gantt-baseline-grid', standalone: true, // Allows Angular demos to bind RevoGrid plugin props that are not wrapper inputs. schemas: [NO_ERRORS_SCHEMA], imports: [UiComponent, UiControlDirective, CommonModule, RevoGrid], template: ` <div class="gantt-example-container"> <div class="gantt-toolbar" style="margin-bottom: 1rem; display: flex; gap: 1rem; align-items: center" > <label style="display: flex; align-items: center; gap: 0.5rem; cursor: pointer" > <input rvControl type="checkbox" [checked]="showBaseline" (change)="toggleBaseline($event)" /> Show Baseline </label> <label style="display: flex; align-items: center; gap: 0.5rem"> Baseline <rv-ui component="Dropdown" [props]="{ className: 'rv-select', source: baselineOptions, value: baselineId, config: { ariaLabel: 'Baseline' }, }" (valueChange)="selectBaseline($event)" /> </label> </div> <revo-grid style="height: 500px" [theme]="theme" [hideAttribution]="true" [plugins]="plugins" [source]="tasks" [columns]="columns" [gantt]="ganttConfig" [ganttDependencies]="dependencies" [ganttCalendars]="calendars" [ganttBaselines]="baselines" ></revo-grid> </div> `, encapsulation: ViewEncapsulation.None,})export class GanttBaselineGridComponent { get baselineOptions() { return this.baselines.map((item) => ({ value: item.id, label: item.name })); }
theme = currentTheme().isDark() ? 'darkCompact' : 'compact'; plugins = [GanttPlugin]; showBaseline = true; baselineId = 'baseline-approved'; ganttConfig = this.createGanttConfig();
toggleBaseline(event: Event) { this.showBaseline = (event.target as HTMLInputElement).checked; this.updateGanttConfig(); }
selectBaseline(value: unknown) { this.baselineId = String(value); this.updateGanttConfig(); }
private createGanttConfig() { return { id: PROJECT_ID, name: 'Website Redesign', version: '1', currency: 'USD', timeZone: 'UTC', primaryCalendarId: CALENDAR_ID, updatedAt: '2026-04-06T00:00:00Z', statusDate: '2026-04-06', zoomPreset: 'week-month' as const, visuals: { showBaseline: this.showBaseline, baselineId: this.baselineId }, }; }
private updateGanttConfig() { this.ganttConfig = this.createGanttConfig(); }
calendars: CalendarEntity[] = [ { id: CALENDAR_ID, name: 'Standard', timeZone: 'UTC', workingDays: [1, 2, 3, 4, 5], holidays: [], hoursPerDay: 8, }, ];
tasks: GanttTaskSourceRow[] = [ { id: 't1', parentId: null, name: 'Design', type: 'summary', workflowStatus: 'in-progress', startDate: '2026-04-06', endDate: '2026-04-27', duration: 18, percentDone: 50, calendarId: CALENDAR_ID, tags: [], }, { id: 't2', parentId: 't1', name: 'Wireframes', type: 'task', workflowStatus: 'done', startDate: '2026-04-06', endDate: '2026-04-10', duration: 5, percentDone: 100, calendarId: CALENDAR_ID, tags: [], }, { id: 't3', parentId: 't1', name: 'Design Review', type: 'milestone', workflowStatus: 'done', startDate: '2026-04-10', endDate: '2026-04-10', duration: 0, percentDone: 100, calendarId: CALENDAR_ID, tags: ['milestone'], }, { id: 't4', parentId: 't1', name: 'Visual Design', type: 'task', workflowStatus: 'in-progress', startDate: '2026-04-13', endDate: '2026-04-27', duration: 13, percentDone: 30, calendarId: CALENDAR_ID, tags: [], }, { id: 't5', parentId: null, name: 'Development', type: 'summary', workflowStatus: 'not-started', startDate: '2026-04-28', endDate: '2026-05-21', duration: 18, percentDone: 0, calendarId: CALENDAR_ID, tags: [], }, { id: 't6', parentId: 't5', name: 'Frontend', type: 'task', workflowStatus: 'not-started', startDate: '2026-04-28', endDate: '2026-05-14', duration: 13, percentDone: 0, calendarId: CALENDAR_ID, tags: [], }, { id: 't7', parentId: 't5', name: 'Backend', type: 'task', workflowStatus: 'not-started', startDate: '2026-04-28', endDate: '2026-05-21', duration: 18, percentDone: 0, calendarId: CALENDAR_ID, tags: [], }, { id: 't8', parentId: null, name: 'Launch', type: 'milestone', workflowStatus: 'not-started', startDate: '2026-05-21', endDate: '2026-05-21', duration: 0, percentDone: 0, calendarId: CALENDAR_ID, tags: ['milestone'], }, ];
dependencies: DependencyEntity[] = [ { id: 'd1', predecessorTaskId: 't2', successorTaskId: 't3', type: 'finish-to-start', lagDays: 0, }, { id: 'd2', predecessorTaskId: 't3', successorTaskId: 't4', type: 'finish-to-start', lagDays: 1, }, { id: 'd3', predecessorTaskId: 't4', successorTaskId: 't6', type: 'finish-to-start', lagDays: 1, }, { id: 'd4', predecessorTaskId: 't4', successorTaskId: 't7', type: 'finish-to-start', lagDays: 1, }, { id: 'd5', predecessorTaskId: 't6', successorTaskId: 't8', type: 'finish-to-start', lagDays: 0, }, { id: 'd6', predecessorTaskId: 't7', successorTaskId: 't8', type: 'finish-to-start', lagDays: 0, }, ];
baselines: BaselineSnapshot[] = [ { id: 'baseline-approved', name: 'Approved Plan', capturedAt: '2026-04-01T08:00:00Z', tasks: [ { taskId: 't1', startDate: '2026-04-06', endDate: '2026-04-24', duration: 120, progressPercent: 0, }, { taskId: 't2', startDate: '2026-04-06', endDate: '2026-04-10', duration: 40, progressPercent: 0, }, { taskId: 't3', startDate: '2026-04-10', endDate: '2026-04-10', duration: 0, progressPercent: 0, }, { taskId: 't4', startDate: '2026-04-13', endDate: '2026-04-24', duration: 80, progressPercent: 0, }, { taskId: 't5', startDate: '2026-04-27', endDate: '2026-05-20', duration: 144, progressPercent: 0, }, { taskId: 't6', startDate: '2026-04-27', endDate: '2026-05-13', duration: 104, progressPercent: 0, }, { taskId: 't7', startDate: '2026-04-27', endDate: '2026-05-20', duration: 144, progressPercent: 0, }, { taskId: 't8', startDate: '2026-05-20', endDate: '2026-05-20', duration: 0, progressPercent: 0, }, ], }, { id: 'baseline-replan', name: 'Replan After Design Slip', capturedAt: '2026-04-15T08:00:00Z', tasks: [ { taskId: 't1', startDate: '2026-04-06', endDate: '2026-04-27', duration: 144, progressPercent: 25, }, { taskId: 't2', startDate: '2026-04-06', endDate: '2026-04-10', duration: 40, progressPercent: 100, }, { taskId: 't3', startDate: '2026-04-10', endDate: '2026-04-10', duration: 0, progressPercent: 100, }, { taskId: 't4', startDate: '2026-04-13', endDate: '2026-04-25', duration: 104, progressPercent: 20, }, { taskId: 't5', startDate: '2026-04-28', endDate: '2026-05-21', duration: 144, progressPercent: 0, }, { taskId: 't6', startDate: '2026-04-28', endDate: '2026-05-14', duration: 104, progressPercent: 0, }, { taskId: 't7', startDate: '2026-04-28', endDate: '2026-05-21', duration: 144, progressPercent: 0, }, { taskId: 't8', startDate: '2026-05-21', endDate: '2026-05-21', duration: 0, progressPercent: 0, }, ], }, ];
columns = [ 'wbs', 'name', 'startDate', 'endDate', 'startVarianceDays', 'finishVarianceDays', 'durationVariance', 'progressVariancePercent', ].map((prop) => createDefaultTaskTableColumn(prop as any));}Adding a Baseline
Section titled “Adding a Baseline”Pass one or more BaselineSnapshot objects via grid.ganttBaselines:
grid.ganttBaselines = [ { id: 'baseline-approved', name: 'Approved Plan', capturedAt: '2026-04-01T08:00:00Z', tasks: [ { taskId: 't1', startDate: '2026-04-06', endDate: '2026-04-22', duration: 13, progressPercent: 0, }, { taskId: 't2', startDate: '2026-04-06', endDate: '2026-04-10', duration: 5, progressPercent: 0, }, { taskId: 't3', startDate: '2026-04-10', endDate: '2026-04-10', duration: 0, progressPercent: 0, }, { taskId: 't4', startDate: '2026-04-13', endDate: '2026-04-22', duration: 8, progressPercent: 0, }, { taskId: 't5', startDate: '2026-04-23', endDate: '2026-05-16', duration: 18, progressPercent: 0, }, { taskId: 't6', startDate: '2026-04-23', endDate: '2026-05-09', duration: 13, progressPercent: 0, }, { taskId: 't7', startDate: '2026-04-23', endDate: '2026-05-16', duration: 18, progressPercent: 0, }, { taskId: 't8', startDate: '2026-05-16', endDate: '2026-05-16', duration: 0, progressPercent: 0, }, ], },];You can also capture a snapshot from the current scheduled state:
const plugins = await grid.getPlugins();const gantt = plugins.find( (plugin) => plugin.constructor?.name === 'GanttPlugin',);const baseline = gantt?.captureBaseline?.({ id: 'baseline-current', name: 'Current Approved Plan', capturedAt: '2026-04-15T08:00:00Z',});
if (baseline) { grid.ganttBaselines = [...(grid.ganttBaselines ?? []), baseline];}Enabling the Overlay
Section titled “Enabling the Overlay”Turn on baseline rendering through the visuals key in your project config:
grid.gantt = { // …required fields visuals: { showBaseline: true, baselineId: 'baseline-approved', // optional — defaults to the latest snapshot },};When showBaseline is true, a translucent bar is drawn behind each live task bar showing its baseline position.
Multiple Baselines
Section titled “Multiple Baselines”You can store several snapshots and switch between them at runtime:
// Initially show the approved plangrid.gantt = { ...config, visuals: { showBaseline: true, baselineId: 'baseline-approved' },};
// Switch to a re-baseline after scope changegrid.gantt = { ...config, visuals: { showBaseline: true, baselineId: 'baseline-replan' },};Variance Columns
Section titled “Variance Columns”When a baseline is visible, each projected task row also exposes optional variance fields:
| Field | Description |
|---|---|
startVarianceDays | Current scheduled start minus baseline start, in calendar days |
finishVarianceDays | Current scheduled finish minus baseline finish, in calendar days |
durationVariance | Current scheduled duration minus baseline duration |
progressVariancePercent | Current progress minus baseline progress, in percentage points |
Add the default columns when users need to inspect drift numerically:
grid.columns = [ createDefaultTaskTableColumn('name'), createDefaultTaskTableColumn('startVarianceDays'), createDefaultTaskTableColumn('finishVarianceDays'), createDefaultTaskTableColumn('durationVariance'), createDefaultTaskTableColumn('progressVariancePercent'),];BaselineSnapshot Fields
Section titled “BaselineSnapshot Fields”| Field | Type | Description |
|---|---|---|
id | BaselineId | Unique identifier for this snapshot |
name | string | Human-readable label (e.g. "Q1 Approved Plan") |
capturedAt | ISODateTimeString | When the snapshot was taken |
tasks | BaselineTaskSnapshot[] | Per-task date and progress records |
BaselineTaskSnapshot Fields
Section titled “BaselineTaskSnapshot Fields”| Field | Type | Description |
|---|---|---|
taskId | TaskId | References the live task |
startDate | ISODateString | Baseline start date |
endDate | ISODateString | Baseline end date |
duration | number | Baseline task duration |
progressPercent | number | Baseline progress (0–100) |