@mogura/moguchart-core 0.5.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024-present Murakami Hiroyuki
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.en.md ADDED
@@ -0,0 +1,491 @@
1
+ # @mogura/moguchart-core
2
+
3
+ A lightweight yet feature-rich Gantt chart Web Component built with Lit. Works with Vue, React, Angular, Svelte, and any other framework.
4
+
5
+ ## Features
6
+
7
+ - 🚀 **Framework-agnostic**: Built as Web Components (Custom Elements), works in any environment.
8
+ - ⚡ **Virtual Scrolling**: Smooth performance even with large numbers of tasks and rows.
9
+ - 🖱️ **Interactive**:
10
+ - Drag & drop task movement (including cross-row moves)
11
+ - Handle-based duration resizing
12
+ - Drag & drop row reordering
13
+ - Column header width resizing
14
+ - Multi-task selection & batch drag (Ctrl/Cmd + click)
15
+ - Double-click and right-click event handling
16
+ - 🎨 **Highly Customizable**:
17
+ - Custom rendering for task bars, row headers, tooltips, and drag info
18
+ - Light/Dark/System theme switching + custom color themes
19
+ - Task bar fill patterns (13 types including stripes, dots, checkerboard, etc.)
20
+ - CSS styling
21
+ - 🔗 **Dependency Visualization**: Curved lines with arrows showing task dependencies (S-curve support for reverse direction)
22
+ - 📅 **Flexible Calendar**:
23
+ - Day / Week / Month view switching
24
+ - Adjustable zoom level (pixels per day or per month) and display period
25
+ - Current time line with badge (auto-refresh support)
26
+ - Custom holiday detection logic
27
+ - Configurable week start day
28
+ - Locale support (Japanese, English, and custom locales)
29
+ - 🏁 **Milestones**: Display milestones (vertical line + name badge) on the chart
30
+ - 📍 **Markers**: Show triangle icons with labels on row timelines
31
+ - ✨ **Advanced Integration**:
32
+ - External drag & drop for task creation
33
+ - Task move/copy mode
34
+ - Snap feature (grid snap by time unit, automatic monthly snap in month view)
35
+ - `hitTest` method for getting row/date from coordinates
36
+ - Programmatic task selection + auto-scroll (`selectTask`)
37
+ - ⌨️ **Keyboard Operations**: Arrow key navigation & selection, Shift+Arrow task movement, Delete key deletion
38
+
39
+ ## Installation
40
+
41
+ ```bash
42
+ pnpm add @mogura/moguchart-core
43
+ # or
44
+ npm install @mogura/moguchart-core
45
+ ```
46
+
47
+ ## API Reference
48
+
49
+ See [API.en.md](./doc/API.en.md) for a detailed API reference.
50
+
51
+ ## Usage with Vue.js
52
+
53
+ Example using Vue.js (Vue 3).
54
+ When using Web Components, you may need to configure your build tool (e.g., `vite.config.ts`) to recognize custom elements.
55
+
56
+ ```html
57
+ <script setup lang="ts">
58
+ import { ref } from 'vue'
59
+ import '@mogura/moguchart-core'
60
+ import type { GanttRow, GanttChartOption, TaskUpdateEventDetail } from '@mogura/moguchart-core'
61
+
62
+ const rows = ref<GanttRow[]>([
63
+ {
64
+ id: 'row-1',
65
+ name: 'Project A',
66
+ tasks: [
67
+ {
68
+ id: 't-1',
69
+ name: 'Task 1',
70
+ start: new Date('2024-01-01'),
71
+ end: new Date('2024-01-05'),
72
+ style: 'background-color: #60a5fa',
73
+ },
74
+ ],
75
+ markers: [
76
+ {
77
+ id: 'marker-1',
78
+ name: 'Review Deadline',
79
+ date: new Date('2024-01-03'),
80
+ type: 'triangle-down',
81
+ color: '#ef4444',
82
+ },
83
+ ],
84
+ },
85
+ ])
86
+
87
+ const option = ref<GanttChartOption>({
88
+ calendar: {
89
+ start: new Date('2024-01-01'),
90
+ end: new Date('2024-03-31'),
91
+ pxPerDay: 30,
92
+ showCurrentTime: true,
93
+ milestones: [
94
+ {
95
+ id: 'ms-1',
96
+ name: 'Release',
97
+ start: new Date('2024-02-01'),
98
+ color: '#8b5cf6',
99
+ },
100
+ ],
101
+ },
102
+ bar: { height: 28 },
103
+ rowHeader: { width: 200 },
104
+ theme: 'system',
105
+ })
106
+
107
+ const handleTaskUpdate = (e: Event) => {
108
+ const detail = (e as CustomEvent<TaskUpdateEventDetail>).detail
109
+ console.log('Task updated:', detail)
110
+ }
111
+ </script>
112
+
113
+ <template>
114
+ <div style="height: 500px;">
115
+ <gantt-chart :rows="rows" :option="option" @task-update="handleTaskUpdate"></gantt-chart>
116
+ </div>
117
+ </template>
118
+ ```
119
+
120
+ ## Usage with React
121
+
122
+ Example using React.
123
+ Since Web Components require direct property and event handling, use `ref` for implementation.
124
+
125
+ ```tsx
126
+ import { useEffect, useRef, useState } from 'react'
127
+ import '@mogura/moguchart-core'
128
+ import type { GanttRow, GanttChartOption, TaskUpdateEventDetail } from '@mogura/moguchart-core'
129
+
130
+ // Type definition for TypeScript
131
+ declare global {
132
+ namespace JSX {
133
+ interface IntrinsicElements {
134
+ 'gantt-chart': any
135
+ }
136
+ }
137
+ }
138
+
139
+ export default function App() {
140
+ const chartRef = useRef<any>(null)
141
+
142
+ const [rows] = useState<GanttRow[]>([
143
+ {
144
+ id: 'row-1',
145
+ name: 'Project A',
146
+ tasks: [
147
+ {
148
+ id: 't-1',
149
+ name: 'Task 1',
150
+ start: new Date('2024-01-01'),
151
+ end: new Date('2024-01-05'),
152
+ style: 'background-color: #60a5fa',
153
+ },
154
+ ],
155
+ markers: [
156
+ {
157
+ id: 'marker-1',
158
+ name: 'Review Deadline',
159
+ date: new Date('2024-01-03'),
160
+ type: 'triangle-down',
161
+ color: '#ef4444',
162
+ },
163
+ ],
164
+ },
165
+ ])
166
+
167
+ const [option] = useState<GanttChartOption>({
168
+ calendar: {
169
+ start: new Date('2024-01-01'),
170
+ end: new Date('2024-03-31'),
171
+ pxPerDay: 30,
172
+ showCurrentTime: true,
173
+ milestones: [
174
+ {
175
+ id: 'ms-1',
176
+ name: 'Release',
177
+ start: new Date('2024-02-01'),
178
+ color: '#8b5cf6',
179
+ },
180
+ ],
181
+ },
182
+ bar: { height: 28 },
183
+ rowHeader: { width: 200 },
184
+ theme: 'system',
185
+ })
186
+
187
+ useEffect(() => {
188
+ const chart = chartRef.current
189
+ if (!chart) return
190
+
191
+ // Set properties
192
+ chart.rows = rows
193
+ chart.option = option
194
+
195
+ // Set up event listeners
196
+ const handleTaskUpdate = (e: Event) => {
197
+ const detail = (e as CustomEvent<TaskUpdateEventDetail>).detail
198
+ console.log('Task updated:', detail)
199
+ }
200
+
201
+ chart.addEventListener('task-update', handleTaskUpdate)
202
+
203
+ return () => {
204
+ chart.removeEventListener('task-update', handleTaskUpdate)
205
+ }
206
+ }, [rows, option])
207
+
208
+ return (
209
+ <div style={{ height: '500px' }}>
210
+ <gantt-chart ref={chartRef}></gantt-chart>
211
+ </div>
212
+ )
213
+ }
214
+ ```
215
+
216
+ ## Key Features
217
+
218
+ ### Themes
219
+
220
+ Three theme modes are supported: light, dark, and system. Individual colors can be overridden using `customTheme`.
221
+
222
+ ```javascript
223
+ const option = {
224
+ theme: 'dark', // 'light' | 'dark' | 'system'
225
+ customTheme: {
226
+ bg: '#1a1a2e',
227
+ text: '#e0e0e0',
228
+ currentTimeLine: '#ff6b6b',
229
+ },
230
+ // ...
231
+ }
232
+ ```
233
+
234
+ ### Dependency Line Settings
235
+
236
+ Customize the dependency line display with the `dependency` option. Control arrow visibility and size.
237
+ Reverse-direction (right-to-left) dependencies are automatically rendered with S-curves, with horizontal connections at contact points.
238
+
239
+ ```javascript
240
+ const option = {
241
+ dependency: {
242
+ showArrows: true, // Show arrows (default: true)
243
+ arrowSize: 12, // Arrow size in px (default: 8)
244
+ },
245
+ // ...
246
+ }
247
+ ```
248
+
249
+ ### Internationalization (i18n)
250
+
251
+ moguchart-core provides built-in locale support. Japanese is the default locale for backward compatibility. Switch to English or create custom locales.
252
+
253
+ ```javascript
254
+ import { enLocale } from '@mogura/moguchart-core'
255
+
256
+ const option = {
257
+ locale: enLocale,
258
+ // ...
259
+ }
260
+ ```
261
+
262
+ To create a custom locale, implement the `MoguchartLocale` interface:
263
+
264
+ ```typescript
265
+ import type { MoguchartLocale } from '@mogura/moguchart-core'
266
+
267
+ const frLocale: MoguchartLocale = {
268
+ monthFormat: 'MMM YYYY',
269
+ monthRowFormat: 'MMM',
270
+ dateFormat: (d) => `${d.getDate()}/${d.getMonth() + 1}/${d.getFullYear()}`,
271
+ timeUnitDateFormat: (d) => `${d.getDate()} ${['jan', 'fév', 'mar', 'avr', 'mai', 'jun', 'jul', 'aoû', 'sep', 'oct', 'nov', 'déc'][d.getMonth()]} ${d.getFullYear()}`,
272
+ dateTimeFormat: (d) => {
273
+ const date = `${d.getDate()}/${d.getMonth() + 1}/${d.getFullYear()}`
274
+ const h = d.getHours()
275
+ const m = d.getMinutes()
276
+ if (h === 0 && m === 0) return date
277
+ return `${date} ${h.toString().padStart(2, '0')}:${m.toString().padStart(2, '0')}`
278
+ },
279
+ yearMonthFormat: (d) => `${d.getFullYear()}/${d.getMonth() + 1}`,
280
+ duration: {
281
+ days: (n) => `${n} jour${n > 1 ? 's' : ''}`,
282
+ hours: (n) => `${n} heure${n > 1 ? 's' : ''}`,
283
+ minutes: (n) => `${n} minute${n > 1 ? 's' : ''}`,
284
+ zero: '0 minute',
285
+ },
286
+ tooltip: { duration: (d) => `Durée: ${d} jour${d > 1 ? 's' : ''}` },
287
+ dragOverlay: {
288
+ noTitle: 'Sans titre',
289
+ moveTo: (name) => `Déplacer vers: ${name}`,
290
+ movingTasks: (c) => `Déplacement de ${c} tâche${c > 1 ? 's' : ''}`,
291
+ },
292
+ }
293
+ ```
294
+
295
+ ### Milestones
296
+
297
+ Pass an array of milestones to `calendar.milestones` to display vertical lines and badges on the chart. Hover effects transition opacity on mouseover.
298
+
299
+ ```javascript
300
+ option.calendar.milestones = [
301
+ {
302
+ id: 'ms-1',
303
+ name: 'Alpha Release',
304
+ start: new Date('2025-04-08'),
305
+ color: '#8b5cf6',
306
+ width: 4,
307
+ },
308
+ {
309
+ id: 'ms-2',
310
+ name: 'Production Release',
311
+ start: new Date('2025-05-01'),
312
+ color: '#10b981',
313
+ },
314
+ ]
315
+ ```
316
+
317
+ ### Markers
318
+
319
+ Pass an array of markers to each row's `markers` property to display triangle icons with labels on the timeline.
320
+
321
+ ```javascript
322
+ const rows = [
323
+ {
324
+ id: 'row-1',
325
+ name: 'Task A',
326
+ tasks: [
327
+ /* ... */
328
+ ],
329
+ markers: [
330
+ {
331
+ id: 'marker-1',
332
+ name: 'Review Deadline',
333
+ date: new Date('2025-04-10'),
334
+ anchor: 'end',
335
+ type: 'triangle-right',
336
+ color: '#ef4444',
337
+ },
338
+ ],
339
+ },
340
+ ]
341
+ ```
342
+
343
+ ### Task Bar Patterns
344
+
345
+ Apply 13 types of fill patterns to task bars. Preset constants are also available.
346
+
347
+ ```javascript
348
+ import { PATTERN_DIAGONAL_STRIPE } from '@mogura/moguchart-core'
349
+
350
+ const task = {
351
+ id: 't-1',
352
+ name: 'WIP',
353
+ start: new Date('2024-01-01'),
354
+ end: new Date('2024-01-05'),
355
+ style: 'background-color: #60a5fa',
356
+ pattern: PATTERN_DIAGONAL_STRIPE, // Use preset
357
+ // or specify directly:
358
+ // pattern: { type: 'checkerboard', color: '#ffffff80' }
359
+ }
360
+ ```
361
+
362
+ Available patterns: `diagonal-stripe` `diagonal-stripe-thin` `diagonal-stripe-thick` `diagonal-stripe-reverse` `vertical-stripe` `horizontal-stripe` `checkerboard` `dots` `dots-dense` `triangle` `circle` `grid` `diagonal-grid`
363
+
364
+ ### Row Reordering
365
+
366
+ Set `enableRowReordering: true` to enable drag & drop row reordering.
367
+
368
+ ```javascript
369
+ const option = {
370
+ enableRowReordering: true,
371
+ // ...
372
+ }
373
+
374
+ chart.addEventListener('row-reordered', (e) => {
375
+ console.log('Reordered rows:', e.detail.rows)
376
+ })
377
+ ```
378
+
379
+ ### Multi-Task Selection & Batch Operations
380
+
381
+ Hold `Ctrl` (Mac: `Cmd`) and click task bars to select multiple tasks, then drag them together.
382
+
383
+ ```javascript
384
+ chart.addEventListener('task-update', (e) => {
385
+ const detail = e.detail
386
+ if (!detail.isDragging && detail.selectedTaskIds?.length > 1) {
387
+ // Multi-selection drag drop: apply same dx to all selected tasks
388
+ for (const taskId of detail.selectedTaskIds) {
389
+ applyDxToTask(taskId, detail.dx)
390
+ }
391
+ }
392
+ })
393
+ ```
394
+
395
+ ### Snap Feature
396
+
397
+ Control the snap interval when dragging tasks with `snapDuration` (in minutes). When using monthly view mode (`pxPerMonth`), snapping is automatically enforced at monthly boundaries.
398
+
399
+ ```javascript
400
+ const option = {
401
+ snapDuration: 60, // Snap every hour (default: 1440 = 1 day)
402
+ // ...
403
+ }
404
+ ```
405
+
406
+ ### View Modes
407
+
408
+ #### Week View Mode
409
+
410
+ Set `calendar.showWeeks: true` for a two-row calendar header with week numbers. This mode is enabled automatically when `pxPerDay` is less than 20.
411
+
412
+ ```javascript
413
+ const option = {
414
+ calendar: {
415
+ start: new Date('2025-01-01'),
416
+ end: new Date('2025-12-31'),
417
+ pxPerDay: 15,
418
+ showWeeks: true,
419
+ weekStartDay: 1, // 1 = Monday (default)
420
+ weekFormat: (weekNum) => `W${weekNum}`,
421
+ },
422
+ }
423
+ ```
424
+
425
+ #### Monthly View Mode
426
+
427
+ Set `calendar.pxPerMonth` to render each month at a fixed equal width. Snapping is automatically enforced at monthly boundaries.
428
+
429
+ ```javascript
430
+ const option = {
431
+ calendar: {
432
+ start: new Date('2025-01-01'),
433
+ end: new Date('2027-12-31'),
434
+ pxPerDay: 1,
435
+ pxPerMonth: 120, // 120px per month
436
+ showMonthsRow: true, // Two-row header: top=year, bottom=month
437
+ },
438
+ }
439
+ ```
440
+
441
+ ### Public Methods
442
+
443
+ #### selectTask
444
+
445
+ Selects the task with the specified ID and auto-scrolls if it's off-screen.
446
+
447
+ ```javascript
448
+ const chart = document.querySelector('gantt-chart')
449
+ const found = chart.selectTask('task-1')
450
+ ```
451
+
452
+ #### hitTest
453
+
454
+ Returns the corresponding row ID and date from client coordinates (pixel position on screen).
455
+
456
+ ```javascript
457
+ document.addEventListener('mousemove', (e) => {
458
+ const result = chart.hitTest(e.clientX, e.clientY)
459
+ if (result) {
460
+ console.log(`Row: ${result.rowId}, Date: ${result.date}`)
461
+ }
462
+ })
463
+ ```
464
+
465
+ ### Keyboard Operations
466
+
467
+ When the Gantt chart has focus, you can navigate, select, move, and delete tasks using the keyboard.
468
+
469
+ | Key | Action |
470
+ | :--- | :--- |
471
+ | `←` `→` | Move focus between tasks |
472
+ | `↑` `↓` | Move focus to another row |
473
+ | `Enter` / `Space` | Select the focused task |
474
+ | `Ctrl/Cmd + Enter` | Toggle selection (multi-select) |
475
+ | `Shift + ←` `→` | Move selected tasks |
476
+ | `Delete` / `Backspace` | Fire `task-delete` event |
477
+ | `Escape` | Clear selection and focus |
478
+
479
+ ```javascript
480
+ const option = {
481
+ keyboard: {
482
+ enabled: true, // Default: true
483
+ moveStep: 60, // Move amount per Shift+Arrow key press (minutes)
484
+ },
485
+ // ...
486
+ }
487
+ ```
488
+
489
+ ## License
490
+
491
+ MIT