Working Calendar
A working calendar (calendar: { workingDays, holidays }): non-working days are shaded and muted, holidays are tinted and named, tasks given as start + duration count working days, the Duration column counts working days and dragging keeps a task's working-day length while skipping the closed days. Below 960 px the grid switches to a task/progress summary; all task data are retained. Use a wider view for the full columns.
Open the chart without page chrome ↗Drawing width at least 1,024 px. Scroll within the chart on smaller screens.
const options = {
"responsive": [
{
"breakpoint": 960,
"options": {
"plotOptions": {
"gantt": {
"grid": {
"width": 180,
"columns": [
{
"key": "name",
"header": "Task / progress",
"value": (_raw, { task }) => (Number.isFinite(task.progress) ? Math.round(task.progress) + '% · ' : '') + task.name
}
]
}
}
}
}
}
],
"chart": {
"height": "auto",
"toolbar": {
"show": false
},
"type": "gantt",
"events": {
"taskChange": (e, ctx, o) => {
const message = o.task.name + ' → ' + new Date(o.start).toDateString() + ' – ' + new Date(o.end - 1).toDateString()
const output = ctx.el && ctx.el.ownerDocument && ctx.el.ownerDocument.querySelector('#stage .g-log')
if (output) output.textContent = message
else console.log(message)
}
}
},
"series": [
{
"name": "Release 7.2",
"data": [
{
"id": "a",
"name": "API hardening",
"start": "2026-11-16",
"duration": 5,
"progress": 80
},
{
"id": "b",
"name": "Billing webhooks",
"start": "2026-11-19",
"duration": 6,
"progress": 40,
"dependsOn": [
"a"
]
},
{
"id": "c",
"name": "Invoice PDFs",
"start": "2026-11-25",
"duration": 4,
"progress": 10,
"dependsOn": [
"b"
]
},
{
"id": "d",
"name": "Load test",
"start": "2026-12-01",
"duration": 2,
"dependsOn": [
"c"
]
},
{
"id": "e",
"name": "Release",
"start": "2026-12-03",
"milestone": true,
"dependsOn": [
"d"
]
}
]
}
],
"plotOptions": {
"gantt": {
"today": {
"show": false
},
"drag": {
"enabled": true
},
"calendar": {
"workingDays": [
1,
2,
3,
4,
5
],
"holidays": [
{
"date": "2026-11-26",
"name": "Thanksgiving"
},
{
"date": "2026-11-27",
"name": "Day after"
}
]
},
"grid": {
"width": 310,
"columns": [
"name",
{
"key": "start",
"width": 64
},
{
"key": "duration",
"width": 48
}
]
},
"range": {
"min": 1794610800000,
"max": 1796511600000
}
}
},
"theme": {
"mode": "light",
"preset": "coastal"
}
}
const chart = new WestCoastCharts(document.querySelector('#chart'), options)
chart.render()import WestCoastCharts from 'west-coast-charts'
import types from 'west-coast-charts/types'
import premium from 'west-coast-charts/premium'
WestCoastCharts.use(types).use(premium)
const WestCoastChartsPremium = premium
WestCoastCharts.setLicenseKey(LICENCE_KEY) // paid production licence; localhost evaluation needs no key
const options = {
"responsive": [
{
"breakpoint": 960,
"options": {
"plotOptions": {
"gantt": {
"grid": {
"width": 180,
"columns": [
{
"key": "name",
"header": "Task / progress",
"value": (_raw, { task }) => (Number.isFinite(task.progress) ? Math.round(task.progress) + '% · ' : '') + task.name
}
]
}
}
}
}
}
],
"chart": {
"height": "auto",
"toolbar": {
"show": false
},
"type": "gantt",
"events": {
"taskChange": (e, ctx, o) => {
const message = o.task.name + ' → ' + new Date(o.start).toDateString() + ' – ' + new Date(o.end - 1).toDateString()
const output = ctx.el && ctx.el.ownerDocument && ctx.el.ownerDocument.querySelector('#stage .g-log')
if (output) output.textContent = message
else console.log(message)
}
}
},
"series": [
{
"name": "Release 7.2",
"data": [
{
"id": "a",
"name": "API hardening",
"start": "2026-11-16",
"duration": 5,
"progress": 80
},
{
"id": "b",
"name": "Billing webhooks",
"start": "2026-11-19",
"duration": 6,
"progress": 40,
"dependsOn": [
"a"
]
},
{
"id": "c",
"name": "Invoice PDFs",
"start": "2026-11-25",
"duration": 4,
"progress": 10,
"dependsOn": [
"b"
]
},
{
"id": "d",
"name": "Load test",
"start": "2026-12-01",
"duration": 2,
"dependsOn": [
"c"
]
},
{
"id": "e",
"name": "Release",
"start": "2026-12-03",
"milestone": true,
"dependsOn": [
"d"
]
}
]
}
],
"plotOptions": {
"gantt": {
"today": {
"show": false
},
"drag": {
"enabled": true
},
"calendar": {
"workingDays": [
1,
2,
3,
4,
5
],
"holidays": [
{
"date": "2026-11-26",
"name": "Thanksgiving"
},
{
"date": "2026-11-27",
"name": "Day after"
}
]
},
"grid": {
"width": 310,
"columns": [
"name",
{
"key": "start",
"width": 64
},
{
"key": "duration",
"width": 48
}
]
},
"range": {
"min": 1794610800000,
"max": 1796511600000
}
}
},
"theme": {
"mode": "light",
"preset": "coastal"
}
}
const chart = new WestCoastCharts(document.querySelector('#chart'), options)
await chart.render() Waiting for the chart.
Open Data & agent view to read this chart through chart.describe().
Read from the running library through its optional agent/describe module. Text, table and JSON share the same snapshot. Demo data only.
$ wcc chart export gantt-working-calendar.json --out gantt-working-calendar.svg --with-table Public agent tools 0.2.3, tested with Library 1.1.5; available from the versioned GitHub release and npm. Save a JSON spec first and check the loaded runtime and supported modules before rendering. Command reference
Loading /gallery/gantt/working-calendar/index.md … This example uses Premium modules. Compare licences · Embedding in a distributed product?