diff --git a/README.md b/README.md index e23d4ab..0bc5ff6 100644 --- a/README.md +++ b/README.md @@ -45,7 +45,7 @@ Or from the CDN: ``` -Star using Gantt: +Start using Gantt: ```js let tasks = [ { @@ -60,9 +60,82 @@ let tasks = [ let gantt = new Gantt("#gantt", tasks); ``` - +### Configuration +Frappe Gantt offers a wide range of options to customize your chart. +| **Option** | **Description** | **Possible Values** | **Default** | +|---------------------------|---------------------------------------------------------------------------------|----------------------------------------------------|------------------------------------| +| `arrow_curve` | Curve radius of arrows connecting dependencies. | Any positive integer. | `5` | +| `auto_move_label` | Move task labels when user scrolls horizontally. | `true`, `false` | `false` | +| `bar_corner_radius` | Radius of the task bar corners (in pixels). | Any positive integer. | `3` | +| `bar_height` | Height of task bars (in pixels). | Any positive integer. | `30` | +| `container_height` | Height of the container. | `auto` - dynamic container height to fit all tasks - _or_ any positive integer (for pixels). | `auto` | +| `column_width` | Width of each column in the timeline. | Any positive integer. | 45 | +| `date_format` | Format for displaying dates. | Any valid JS date format string. | `YYYY-MM-DD` | +| `upper_header_height` | Height of the upper header in the timeline (in pixels). | Any positive integer. | `45` | +| `lower_header_height` | Height of the lower header in the timeline (in pixels). | Any positive integer. | `30` | +| `snap_at` | Snap tasks at particular intervel while resizing or dragging. | Any _interval_ (see below) | `1d` | +| `infinite_padding` | Whether to extend timeline infinitely when user scrolls. | `true`, `false` | `true` | +| `holidays` | Highlighted holidays on the timeline. | Object mapping CSS colors to holiday types. Types can either be a) 'weekend', or b) array of _strings_ or _date objects_ or _objects_ in the format `{date: ..., label: ...}` | `{ 'var(--g-weekend-highlight-color)': 'weekend' }` | +| `ignore` | Ignored areas in the rendering | `weekend` _or_ Array of strings or date objects (`weekend` can be present to the array also). | `[]` | +| `language` | Language for localization. | ISO 639-1 codes like `en`, `fr`, `es`. | `en` | +| `lines` | Determines which grid lines to display. | `none` for no lines, `vertical` for only vertical lines, `horizontal` for only horizontal lines, `both` for complete grid. | `both` | +| `move_dependencies` | Whether moving a task automatically moves its dependencies. | `true`, `false` | `true` | +| `padding` | Padding around task bars (in pixels). | Any positive integer. | `18` | +| `popup_on` | Event to trigger the popup display. | `click` _or_ `hover` | `click` | +| `readonly_progress` | Disables editing task progress. | `true`, `false` | `false` | +| `readonly_dates` | Disables editing task dates. | `true`, `false` | `false` | +| `readonly` | Disables all editing features. | `true`, `false` | `false` | +| `scroll_to` | Determines the starting point when chart is rendered. | `today`, `start`, `end`, or a date string. | `today` | +| `show_expected_progress` | Shows expected progress for tasks. | `true`, `false` | `false` | +| `today_button` | Adds a button to navigate to today’s date. | `true`, `false` | `true` | +| `view_mode` | The initial view mode of the Gantt chart. | `Day`, `Week`, `Month`, `Year`. | `Day` | +| `view_mode_select` | Allows selecting the view mode from a dropdown. | `true`, `false` | `false` | + +Apart from these ones, two options - `popup` and `view_modes` (plural, not singular) - are available. They have "sub"-APIs, and thus are listed separately. + +#### View Mode Configuration +The `view_modes` option determines all the available view modes for the chart. It should be an array of objects. + +Each object can have the following properties: +- `name` (string) - the name of view mode. +- `padding` (interval) - the time above. +- `step` - the interval of each column +- `lower_text` (date format string _or_ function) - the format for text in lower header. Blank string for none. The function takes in `currentDate`, `previousDate`, and `lang`, and should return a string. +- `upper_text` (date format string _or_ function) - the format for text in upper header. Blank string for none. The function takes in `currentDate`, `previousDate`, and `lang`, and should return a string. +- `upper_text_frequency` (number) - how often the upper text has a value. Utilized in internal calculation to improve performance. +- `thick_line` (function) - takes in `currentDate`, returns Boolean determining whether the line for that date should be thicker than the others. + +Three other options allow you to override general configuration for this view mode alone: +- `format_string` +- `column_width` +- `snap_at` +For details, see the above table. + +#### Popup Configuration +`popup` is a function. If it returns +- `false`, there will be no popup. +- `undefined`, the popup will be rendered based on manipulation within the function +- a HTML string, the popup will be that string. + +The function receives one object as an argument, containing: +- `task` - the task as an object +- `chart` - the entire Gantt chart +- `get_title`, `get_subtitle`, `get_details` (functions) - get the relevant section as a HTML node. +- `set_title`, `set_subtitle`, `set_details` (functions) - take in the HTML of the relevant section +- `add_action` (function) - accepts two parameters, `html` and `func` - respectively determining the HTML of the action and the callback when the action is pressed. + +### API +Frappe Gantt exposes a few helpful methods for you to interact with the chart: + +| **Name** | **Description** | **Parameters** | +|---------------------------|---------------------------------------------------------------------------------|------------------------------------------| +| `.update_options` | Re-renders the chart after updating specific options. | `new_options` - object containing new options. | +| `.change_view_mode` | Updates the view mode. | `view_mode` - Name of view mode _or_ view mode object (see above) and `maintain_pos` - whether to go back to current scroll position after rerendering, defaults to `false`. | +| `.scroll_current` | Scrolls to the current date | No parameters. | +| `.update_task` | Re-renders a specific task bar alone | `task_id` - id of task and `new_details` - object containing the task properties to be updated. | + ## Development Setup If you want to contribute enhancements or fixes: diff --git a/src/defaults.js b/src/defaults.js index 329a97b..462ed6c 100644 --- a/src/defaults.js +++ b/src/defaults.js @@ -89,7 +89,7 @@ const DEFAULT_VIEW_MODES = [ ? date_utils.format(d, 'YYYY', lang) : '', thick_line: (d) => d.getMonth() % 3 === 0, - default_snap: '7d', + snap_at: '7d', }, { name: 'Year', @@ -100,7 +100,7 @@ const DEFAULT_VIEW_MODES = [ upper_text: (d, ld, lang) => !ld || getDecade(d) !== getDecade(ld) ? getDecade(d) : '', lower_text: 'YYYY', - default_snap: '30d', + snap_at: '30d', }, ]; @@ -119,7 +119,7 @@ const DEFAULT_OPTIONS = { holidays: { 'var(--g-weekend-highlight-color)': 'weekend' }, ignore: [], language: 'en', - lines: 'none', + lines: 'both', move_dependencies: true, padding: 18, popup: (ctx) => { @@ -145,12 +145,16 @@ const DEFAULT_OPTIONS = { if (!ctx.chart.options.readonly) { if (!ctx.chart.options.readonly_progress) { ctx.add_action('+', (task, chart) => { - task.progress += (1 / task.actual_duration) * 100; - chart.update_task(task); + chart.update_task(task.id, { + progress: + task.progress + (1 / task.actual_duration) * 100, + }); }); ctx.add_action('-', (task, chart) => { - task.progress -= (1 / task.actual_duration) * 100; - chart.update_task(task); + chart.update_task(task.id, { + progress: + task.progress - (1 / task.actual_duration) * 100, + }); }); } } diff --git a/src/index.js b/src/index.js index e00b781..b62c400 100644 --- a/src/index.js +++ b/src/index.js @@ -217,17 +217,19 @@ export default class Gantt { this.change_view_mode(); } - update_task(task) { + update_task(id, new_details) { + let task = this.tasks.find((t) => t.id === id); let bar = this.bars[task._index]; + Object.assign(task, new_details); bar.refresh(); } - change_view_mode(mode = this.options.view_mode, change = false) { + change_view_mode(mode = this.options.view_mode, maintain_pos = false) { if (typeof mode === 'string') { mode = this.options.view_modes.find((d) => d.name === mode); } let old_scroll_op, old_scroll_pos; - if (change) { + if (maintain_pos) { old_scroll_op = this.options.scroll_to; this.options.scroll_to = null; old_scroll_pos = this.$container.scrollLeft; @@ -235,9 +237,9 @@ export default class Gantt { this.options.view_mode = mode.name; this.config.view_mode = mode; this.update_view_scale(mode); - this.setup_dates(change); + this.setup_dates(maintain_pos); this.render(); - if (change) { + if (maintain_pos) { this.options.scroll_to = old_scroll_op; this.$container.scrollLeft = old_scroll_pos; } @@ -491,7 +493,7 @@ export default class Gantt { let $today_button = document.createElement('button'); $today_button.classList.add('today-button'); $today_button.textContent = 'Today'; - $today_button.onclick = this.scroll_today.bind(this); + $today_button.onclick = this.scroll_current.bind(this); this.$side_header.prepend($today_button); this.$today_button = $today_button; } @@ -560,7 +562,7 @@ export default class Gantt { } } - highlightHolidays() { + highlight_holidays() { let labels = {}; if (!this.options.holidays) return; @@ -654,7 +656,7 @@ export default class Gantt { * * @returns Object containing the x-axis distance and date of the current date, or null if the current date is out of the gantt range. */ - highlightNow() { + highlight_current() { const res = this.get_closest_date(); if (!res) return; @@ -691,7 +693,7 @@ export default class Gantt { } make_grid_highlights() { - this.highlightHolidays(); + this.highlight_holidays(); this.config.ignored_positions = []; const height = @@ -735,7 +737,9 @@ export default class Gantt { }); } - const highlightDimensions = this.highlightNow(this.config.view_mode); + const highlightDimensions = this.highlight_current( + this.config.view_mode, + ); if (!highlightDimensions) return; } @@ -904,7 +908,7 @@ export default class Gantt { } else if (date === 'end') { date = this.gantt_end; } else if (date === 'today') { - return this.scroll_today(); + return this.scroll_current(); } else if (typeof date === 'string') { date = date_utils.parse(date); } @@ -962,7 +966,7 @@ export default class Gantt { this.$current = $el; } - scroll_today() { + scroll_current() { let res = this.get_closest_date(); if (res) this.set_scroll_position(res[0]); } @@ -1420,7 +1424,7 @@ export default class Gantt { get_snap_position(dx, ox) { let unit_length = 1; const default_snap = - this.options.snap_at || this.config.view_mode.default_snap || '1d'; + this.options.snap_at || this.config.view_mode.snap_at || '1d'; if (default_snap !== 'unit') { const { duration, scale } = date_utils.parse_duration(default_snap);