@irricrops/carpincho
v0.1.0
Published
Extensible hourly Gantt chart library built with Konva.js
Maintainers
Readme
Carpincho
Extensible hourly Gantt chart library built with Konva.js.
Features
- Hour-based timeline (zoom from 1h to 15 days per viewport)
- Hierarchical rows with collapsible groups
- Draggable, resizable tasks (edit mode)
- Pan with middle-mouse or Shift+wheel
- Zoom with Ctrl+wheel
- Light/Dark themes
- Context menus: header, sidebar, grid, task
- Customizable tooltips
- TypeScript support
Installation
npm install @irricrops/carpinchoPeer dependency (must be installed separately):
npm install konvaInstall from git (without npm)
npm install github:irricrops/carpincho
# or specific branch
npm install github:irricrops/carpincho#mainUsage
<div id="gantt-container" style="width: 800px; height: 400px;"></div>
<script type="module">
import Carpincho from '@irricrops/carpincho';
const gantt = new Carpincho(document.getElementById('gantt-container'), {
start: new Date('2026-04-15T00:00:00'),
end: new Date('2026-04-22T00:00:00'),
rows: [
{
id: 'row-1',
label: 'Irrigation Zone A',
columns: { status: 'Active', flow: '120 L/h' },
tasks: [
{ id: 't1', start: new Date('2026-04-15T08:00'), end: new Date('2026-04-15T12:00'), label: 'Morning irrigation', color: '#4a90d9' }
]
}
],
rowHeight: 90,
sidebarWidth: 190,
timezone: 'America/Santiago',
columns: [
{ key: 'status', label: 'Status', width: 80 },
{ key: 'flow', label: 'Flow', width: 75 }
]
});
</script>API
Options
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| start | Date | required | Timeline start |
| end | Date | required | Timeline end |
| rows | Row[] | [] | Initial rows/groups |
| rowHeight | number | 120 | Height per row in pixels |
| sidebarWidth | number | 200 | Sidebar width |
| sidebarLabel | string | 'Name' | Sidebar header label |
| columns | ColumnDef[] | [] | Sidebar columns |
| timezone | string | 'UTC' | IANA timezone |
| locale | string | 'es-ES' | Date formatting locale |
| theme | 'light' | 'dark' | 'light' | Color theme |
| editMode | boolean | false | Enable task dragging |
| readonly | boolean | false | Disable all interactions |
| snapMs | number | 300000 | Snap interval (5 min) |
| portalTarget | HTMLElement | document.body | Tooltip/menu container |
| tooltipRenderer | function | null | Custom tooltip HTML |
Methods
gantt.setRows(rows) // Replace all rows
gantt.addRow(row) // Add a row
gantt.removeRow(id) // Remove a row
gantt.toggleGroup(id) // Collapse/expand group
gantt.addTask(itemId, task) // Add task to row
gantt.updateTask(itemId, taskId, patch) // Update task
gantt.removeTask(itemId, taskId) // Remove task
gantt.setEditMode(enabled) // Toggle edit mode
gantt.setColumns(cols) // Update sidebar columns
gantt.scrollTo(date) // Scroll to date
gantt.zoom(dir) // Zoom in/out (+1/-1)
gantt.extendRange(dir, ms) // Extend timeline range
gantt.setTheme('dark') // Switch theme
gantt.setMenuItems(key, items) // Configure context menus
gantt.on(event, fn) // Subscribe to events
gantt.destroy() // CleanupEvents
gantt.on('task:click', ({ item, task }) => {})
gantt.on('task:dblclick', ({ item, task, clientX, clientY }) => {})
gantt.on('task:moved', ({ itemId, taskId, start, end }) => {})
gantt.on('gantt:dblclick', ({ date, rowItem, rowType, clientX, clientY }) => {})
gantt.on('contextmenu:header', ({ date, clientX, clientY }) => {})
gantt.on('contextmenu:sidebar', ({ item, rowType, clientX, clientY }) => {})
gantt.on('contextmenu:grid', ({ item, rowType, date, clientX, clientY }) => {})
gantt.on('contextmenu:task', ({ task, item, date, clientX, clientY }) => {})
gantt.on('editmode:changed', ({ editMode }) => {})Context Menus
Configure menus for different zones:
gantt.setMenuItems('header', [
{ label: 'Zoom to day', action: () => {} },
{ label: 'Zoom to week', action: () => {} },
{ separator: true },
{ label: 'Add task', action: () => {}, disabled: true }
]);
gantt.setMenuItems('grid', [
{ label: 'Add task here', action: (p) => console.log(p.date) },
{ label: 'Add row', action: () => {} }
]);
gantt.setMenuItems('task', [
{ label: 'Edit task', action: (p) => {} },
{ label: 'Delete', action: (p) => {}, danger: true }
]);
gantt.setMenuItems('sidebar', [
{ label: 'Add row', action: () => {} },
{ label: 'Delete row', action: () => {}, danger: true }
]);Menu item options:
label: button textaction(payload): click handlerdanger: red stylingdisabled: greyed outseparator: divider line
Development
npm install
npm run dev # Start demo server
npm run build # Build for productionLicense
MIT
