Skip to content

Advanced Examples

This section shows advanced usage patterns and complex scenarios.

Drag Limits and Constraints

vue
<template>
  <g-gantt-chart
    v-bind="chartConfig"
    :push-on-overlap="true"
    :no-overlap="true"
  >
    <g-gantt-row
      v-for="row in rows"
      :key="row.label"
      :label="row.label"
      :bars="row.bars"
    />
  </g-gantt-chart>
</template>

<script setup lang="ts">
const rows = ref([
  {
    label: 'Constrained Tasks',
    bars: [
      {
        start: '2024-01-01',
        end: '2024-01-15',
        ganttBarConfig: {
          id: '1',
          label: 'Immobile Task',
          immobile: true
        }
      },
      {
        start: '2024-01-16',
        end: '2024-01-30',
        ganttBarConfig: {
          id: '2',
          label: 'Movable Task',
          pushOnOverlap: true
        }
      }
    ]
  }
])
</script>

Complex Project Example

vue
<template>
  <g-gantt-chart
    v-bind="chartConfig"
    :enable-connections="true"
    :push-on-overlap="true"
    :push-on-connect="true"
  >
    <template #label-column-title>
      <div class="custom-header">
        Project Timeline
      </div>
    </template>

    <g-gantt-row
      v-for="row in rows"
      :key="row.label"
      :label="row.label"
      :bars="row.bars"
    >
      <template #bar-label="{ bar }">
        <div class="custom-bar-label">
          <div>{{ bar.ganttBarConfig.label }}</div>
          <div class="progress">
            {{ bar.progress }}%
          </div>
        </div>
      </template>
    </g-gantt-row>
  </g-gantt-chart>
</template>

<script setup lang="ts">
// Complex project data with dependencies and progress tracking
const rows = ref([
  {
    label: 'Planning',
    bars: [{
      start: '2024-01-01',
      end: '2024-01-15',
      progress: 100,
      ganttBarConfig: {
        id: '1',
        label: 'Requirements',
        connections: [{
          targetId: '2',
          type: 'bezier',
          animated: true
        }]
      }
    }]
  },
  // ... additional complex rows
])
</script>

<style scoped>
.custom-bar-label {
  display: flex;
  justify-content: space-between;
  align-items: center;
  width: 100%;
  padding: 0 8px;
}

.progress {
  font-size: 0.8em;
  color: #666;
}
</style>

Planned vs Actual Timeline Tracking

The planned bars feature allows you to visualize both planned and actual timelines for project tracking and variance analysis:

vue
<template>
  <g-gantt-chart
    v-bind="chartConfig"
    :show-planned-bars="true"
  >
    <g-gantt-row
      v-for="row in projectRows"
      :key="row.label"
      :label="row.label"
      :bars="row.bars"
    />
  </g-gantt-chart>
</template>

<script setup lang="ts">
import { ref } from 'vue'

const chartConfig = ref({
  chartStart: '2024-01-01',
  chartEnd: '2024-03-31',
  precision: 'day',
  barStart: 'start',
  barEnd: 'end'
})

const projectRows = ref([
  {
    label: 'Planning Phase',
    bars: [{
      start: '2024-01-03',           // Actual started 2 days late
      end: '2024-01-18',             // Finished 3 days late
      start_planned: '2024-01-01',   // Originally planned start
      end_planned: '2024-01-15',     // Originally planned end
      ganttBarConfig: {
        id: 'planning',
        label: 'Requirements & Design',
        style: {
          backgroundColor: '#4caf50',
          color: 'white'
        },
        plannedStyle: {
          backgroundColor: '#e8f5e8',
          border: '2px dashed #4caf50',
          opacity: 0.6
        }
      }
    }]
  },
  {
    label: 'Development',
    bars: [{
      start: '2024-01-20',           // Started on time
      end: '2024-02-25',             // Running 5 days over
      start_planned: '2024-01-20',   // Planned start
      end_planned: '2024-02-20',     // Planned end
      ganttBarConfig: {
        id: 'development',
        label: 'Core Implementation',
        style: {
          backgroundColor: '#2196f3',
          color: 'white'
        },
        plannedStyle: {
          backgroundColor: '#e3f2fd',
          border: '2px dashed #2196f3',
          opacity: 0.6
        }
      }
    }]
  },
  {
    label: 'Testing',
    bars: [{
      start: '2024-03-01',           // Delayed start due to dev overrun
      end: '2024-03-20',             // Compressed timeline
      start_planned: '2024-02-25',   // Originally planned earlier
      end_planned: '2024-03-15',     // Originally shorter duration
      ganttBarConfig: {
        id: 'testing',
        label: 'QA & Bug Fixes',
        style: {
          backgroundColor: '#ff9800',
          color: 'white'
        },
        plannedStyle: {
          backgroundColor: '#fff3e0',
          border: '2px dashed #ff9800',
          opacity: 0.6
        }
      }
    }]
  }
])
</script>

Project Variance Analysis Example

vue
<template>
  <div class="project-dashboard">
    <h3>Project Dashboard with Variance Tracking</h3>
    
    <!-- Summary Stats -->
    <div class="variance-summary">
      <div class="stat-card">
        <strong>Total Delay:</strong> {{ calculateTotalDelay() }} days
      </div>
      <div class="stat-card">
        <strong>Tasks Over Budget:</strong> {{ tasksOverBudget() }}
      </div>
    </div>

    <g-gantt-chart
      v-bind="chartConfig"
      :show-planned-bars="true"
      @click-bar="handleBarClick"
    >
      <g-gantt-row
        v-for="row in varianceRows"
        :key="row.label"
        :label="row.label"
        :bars="row.bars"
      >
        <template #bar-tooltip="{ bar, barStart, barEnd }">
          <div class="variance-tooltip">
            <h4>{{ bar.ganttBarConfig.label }}</h4>
            <div><strong>Actual:</strong> {{ barStart }} → {{ barEnd }}</div>
            <div v-if="bar.start_planned">
              <strong>Planned:</strong> {{ bar.start_planned }} → {{ bar.end_planned }}
            </div>
            <div class="variance-info">
              <strong>Variance:</strong> 
              <span :class="getVarianceClass(bar)">
                {{ calculateVariance(bar) }}
              </span>
            </div>
          </div>
        </template>
      </g-gantt-row>
    </g-gantt-chart>
  </div>
</template>

<script setup lang="ts">
import dayjs from 'dayjs'

const varianceRows = ref([
  {
    label: 'Frontend Development',
    bars: [{
      start: '2024-01-10',
      end: '2024-02-15',
      start_planned: '2024-01-05',
      end_planned: '2024-02-05',
      ganttBarConfig: {
        id: 'frontend',
        label: 'React Components',
        plannedStyle: {
          backgroundColor: '#ffebee',
          border: '2px dashed #f44336',
          opacity: 0.7
        }
      }
    }]
  },
  {
    label: 'Backend API',
    bars: [{
      start: '2024-01-08',
      end: '2024-01-28',
      start_planned: '2024-01-10',
      end_planned: '2024-02-10',
      ganttBarConfig: {
        id: 'backend',
        label: 'REST API Development',
        plannedStyle: {
          backgroundColor: '#e8f5e8',
          border: '2px dashed #4caf50',
          opacity: 0.7
        }
      }
    }]
  }
])

function calculateVariance(bar) {
  if (!bar.start_planned || !bar.end_planned) return 'N/A'
  
  const actualDuration = dayjs(bar.end).diff(dayjs(bar.start), 'days')
  const plannedDuration = dayjs(bar.end_planned).diff(dayjs(bar.start_planned), 'days')
  const variance = actualDuration - plannedDuration
  
  return variance > 0 ? `+${variance} days` : `${variance} days`
}

function getVarianceClass(bar) {
  if (!bar.start_planned) return ''
  const variance = dayjs(bar.end).diff(dayjs(bar.end_planned), 'days')
  return variance > 0 ? 'over-budget' : variance < 0 ? 'under-budget' : 'on-time'
}

function calculateTotalDelay() {
  return varianceRows.value.reduce((total, row) => {
    return total + row.bars.reduce((rowTotal, bar) => {
      const delay = bar.start_planned 
        ? Math.max(0, dayjs(bar.end).diff(dayjs(bar.end_planned), 'days'))
        : 0
      return rowTotal + delay
    }, 0)
  }, 0)
}

function tasksOverBudget() {
  return varianceRows.value.reduce((count, row) => {
    return count + row.bars.filter(bar => 
      bar.start_planned && dayjs(bar.end).isAfter(dayjs(bar.end_planned))
    ).length
  }, 0)
}

function handleBarClick({ bar }) {
  console.log('Bar clicked:', bar.ganttBarConfig.label)
  // Handle bar interaction
}
</script>

<style scoped>
.project-dashboard {
  padding: 20px;
}

.variance-summary {
  display: flex;
  gap: 20px;
  margin-bottom: 20px;
}

.stat-card {
  padding: 12px;
  background: #f5f5f5;
  border-radius: 6px;
  border-left: 4px solid #2196f3;
}

.variance-tooltip {
  padding: 10px;
  background: white;
  border-radius: 4px;
  box-shadow: 0 2px 8px rgba(0,0,0,0.1);
}

.variance-info {
  margin-top: 8px;
  padding-top: 8px;
  border-top: 1px solid #eee;
}

.over-budget { color: #f44336; font-weight: bold; }
.under-budget { color: #4caf50; font-weight: bold; }
.on-time { color: #2196f3; font-weight: bold; }
</style>

Multi Label Columns

vue
<template>
  <g-gantt-chart
    v-bind="chartConfig"
    :push-on-overlap="true"
    :no-overlap="true"
    label-column-title="Project Details"
    :multi-column-label="multiColumnLabel"
  >
    <g-gantt-row
      v-for="row in rows"
      :key="row.label"
      :label="row.label"
      :bars="row.bars"
    />
  </g-gantt-chart>
</template>

<script setup lang="ts">
const rows = ref([
  {
    label: 'Constrained Tasks',
    bars: [
      {
        start: '2024-01-01',
        end: '2024-01-15',
        ganttBarConfig: {
          id: '1',
          label: 'Immobile Task',
          immobile: true
        }
      },
      {
        start: '2024-01-16',
        end: '2024-01-30',
        ganttBarConfig: {
          id: '2',
          label: 'Movable Task',
          pushOnOverlap: true
        }
      }
    ]
  }
])

const getN = (row: ChartRow) => {
  return row.bars.length
}

const sortN = (a: ChartRow, b: ChartRow) => {
  const aId = a.bars.length ?? 0
  const bId = b.bars.length ?? 0
  return aId < bId ? -1 : aId > bId ? 1 : 0
}


const multiColumnLabel = ref<LabelColumnConfig[]>([
  {
    field: 'Id',
    sortable: false,
  },
  {
    field: 'Label',
  },
  {
    field: 'StartDate',
  },
  {
    field: 'Duration',
  },
  {
    field: 'Bars N°',
    valueGetter: getN,
    sortFn: sortN,
  },
])
</script>

Released under the MIT License.