Merge pull request #454 from moradlarbi/customViews
feat: add support for custom time views
This commit is contained in:
commit
788a96f83c
1293
dist/frappe-gantt.es.js
vendored
1293
dist/frappe-gantt.es.js
vendored
File diff suppressed because it is too large
Load Diff
23
dist/frappe-gantt.umd.js
vendored
23
dist/frappe-gantt.umd.js
vendored
File diff suppressed because one or more lines are too long
13
index.html
13
index.html
@ -101,16 +101,23 @@
|
|||||||
id: i,
|
id: i,
|
||||||
})),
|
})),
|
||||||
];
|
];
|
||||||
|
|
||||||
let gantt_chart = new Gantt('.gantt-target', tasks, {
|
let gantt_chart = new Gantt('.gantt-target', tasks, {
|
||||||
on_click(task) {
|
on_click(task) {
|
||||||
console.log('Click', task);
|
console.log('Click', task);
|
||||||
},
|
},
|
||||||
// on_hover (task, x, y) {
|
// on_hover (task, x, y) {
|
||||||
// console.log("Hover", x, y);
|
// console.log("Hover", x, y);
|
||||||
// },
|
// }
|
||||||
view_mode: 'Year',
|
view_mode: 'Custom Day',
|
||||||
view_mode_padding: { DAY: '3d' },
|
view_mode_padding: { DAY: '3d' },
|
||||||
|
custom_view_modes: [
|
||||||
|
{
|
||||||
|
name: 'Custom Day',
|
||||||
|
padding: '1m',
|
||||||
|
step: 3,
|
||||||
|
unit: "day",
|
||||||
|
}
|
||||||
|
]
|
||||||
// popup_on: 'click',
|
// popup_on: 'click',
|
||||||
// move_dependencies: false,
|
// move_dependencies: false,
|
||||||
// scroll_to: 'today',
|
// scroll_to: 'today',
|
||||||
|
|||||||
239
src/index.js
239
src/index.js
@ -111,11 +111,13 @@ export default class Gantt {
|
|||||||
|
|
||||||
setup_options(options) {
|
setup_options(options) {
|
||||||
this.options = { ...DEFAULT_OPTIONS, ...options };
|
this.options = { ...DEFAULT_OPTIONS, ...options };
|
||||||
if (!options.view_mode_padding) options.view_mode_padding = {};
|
const custom_mode = this.options.custom_view_modes ? this.options.custom_view_modes.find(m => m.name === this.options.view_mode) : null;
|
||||||
for (let [key, value] of Object.entries(options.view_mode_padding)) {
|
if (custom_mode) this.options = {...this.options, custom_mode}
|
||||||
|
if (!this.options.view_mode_padding) this.options.view_mode_padding = {};
|
||||||
|
for (let [key, value] of Object.entries(this.options.view_mode_padding)) {
|
||||||
if (typeof value === 'string') {
|
if (typeof value === 'string') {
|
||||||
// Configure for single value given
|
// Configure for single value given
|
||||||
options.view_mode_padding[key] = [value, value];
|
this.options.view_mode_padding[key] = [value, value];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -123,6 +125,7 @@ export default class Gantt {
|
|||||||
...VIEW_MODE_PADDING,
|
...VIEW_MODE_PADDING,
|
||||||
...options.view_mode_padding,
|
...options.view_mode_padding,
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
setup_tasks(tasks) {
|
setup_tasks(tasks) {
|
||||||
@ -206,7 +209,6 @@ export default class Gantt {
|
|||||||
|
|
||||||
return task;
|
return task;
|
||||||
});
|
});
|
||||||
|
|
||||||
this.setup_dependencies();
|
this.setup_dependencies();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -235,6 +237,23 @@ export default class Gantt {
|
|||||||
|
|
||||||
update_view_scale(view_mode) {
|
update_view_scale(view_mode) {
|
||||||
this.options.view_mode = view_mode;
|
this.options.view_mode = view_mode;
|
||||||
|
const custom_mode = this.options.custom_mode
|
||||||
|
if (custom_mode) {//configure step and column width for custom view case
|
||||||
|
if (custom_mode.unit === "hour") {
|
||||||
|
this.options.step = custom_mode.step;
|
||||||
|
this.options.column_width = 38;
|
||||||
|
} else if (custom_mode.unit === "day") {
|
||||||
|
this.options.step = custom_mode.step * 24;
|
||||||
|
this.options.column_width = 38;
|
||||||
|
} else if (custom_mode.unit === "month") {
|
||||||
|
this.options.step = custom_mode.step * 24 * 30;
|
||||||
|
this.options.column_width = 120;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.options.step = 24;
|
||||||
|
this.options.column_width = 38;
|
||||||
|
}
|
||||||
|
}
|
||||||
if (view_mode === VIEW_MODE.HOUR) {
|
if (view_mode === VIEW_MODE.HOUR) {
|
||||||
this.options.step = 24 / 24;
|
this.options.step = 24 / 24;
|
||||||
this.options.column_width = 38;
|
this.options.column_width = 38;
|
||||||
@ -282,16 +301,22 @@ export default class Gantt {
|
|||||||
if (!this.gantt_end) gantt_end = new Date();
|
if (!this.gantt_end) gantt_end = new Date();
|
||||||
else gantt_end = date_utils.start_of(this.gantt_end, 'day');
|
else gantt_end = date_utils.start_of(this.gantt_end, 'day');
|
||||||
|
|
||||||
// add date padding on both sides
|
const custom_mode = this.options.custom_mode
|
||||||
let viewKey;
|
let [padding_start, padding_end] = [{duration: 1, scale: 'day'},{duration: 1, scale: 'day'}]
|
||||||
for (let [key, value] of Object.entries(VIEW_MODE)) {
|
if (custom_mode) {
|
||||||
if (value === this.options.view_mode) {
|
[padding_start, padding_end] = [custom_mode.padding, custom_mode.padding].map(date_utils.parse_duration)
|
||||||
viewKey = key;
|
}
|
||||||
}
|
else {
|
||||||
|
let viewKey;
|
||||||
|
for (let [key, value] of Object.entries(VIEW_MODE)) {
|
||||||
|
if (value === this.options.view_mode) {
|
||||||
|
viewKey = key;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
[padding_start, padding_end] = this.options.view_mode_padding[
|
||||||
|
viewKey
|
||||||
|
].map(date_utils.parse_duration);
|
||||||
}
|
}
|
||||||
const [padding_start, padding_end] = this.options.view_mode_padding[
|
|
||||||
viewKey
|
|
||||||
].map(date_utils.parse_duration);
|
|
||||||
gantt_start = date_utils.add(
|
gantt_start = date_utils.add(
|
||||||
gantt_start,
|
gantt_start,
|
||||||
-padding_start.duration,
|
-padding_start.duration,
|
||||||
@ -324,19 +349,31 @@ export default class Gantt {
|
|||||||
let cur_date = null;
|
let cur_date = null;
|
||||||
|
|
||||||
while (cur_date === null || cur_date < this.gantt_end) {
|
while (cur_date === null || cur_date < this.gantt_end) {
|
||||||
if (!cur_date) {
|
if (this.options.custom_mode) {
|
||||||
cur_date = date_utils.clone(this.gantt_start);
|
const step = this.options.custom_mode.step || 1;
|
||||||
} else {
|
const unit = this.options.custom_mode.unit || 'day';
|
||||||
if (this.view_is(VIEW_MODE.YEAR)) {
|
|
||||||
cur_date = date_utils.add(cur_date, 1, 'year');
|
if (!cur_date) {
|
||||||
} else if (this.view_is(VIEW_MODE.MONTH)) {
|
cur_date = date_utils.clone(this.gantt_start);
|
||||||
cur_date = date_utils.add(cur_date, 1, 'month');
|
|
||||||
} else {
|
} else {
|
||||||
cur_date = date_utils.add(
|
cur_date = date_utils.add(cur_date, step, unit);
|
||||||
cur_date,
|
}
|
||||||
this.options.step,
|
}
|
||||||
'hour',
|
else {
|
||||||
);
|
if (!cur_date) {
|
||||||
|
cur_date = date_utils.clone(this.gantt_start);
|
||||||
|
} else {
|
||||||
|
if (this.view_is(VIEW_MODE.YEAR)) {
|
||||||
|
cur_date = date_utils.add(cur_date, 1, 'year');
|
||||||
|
} else if (this.view_is(VIEW_MODE.MONTH)) {
|
||||||
|
cur_date = date_utils.add(cur_date, 1, 'month');
|
||||||
|
} else {
|
||||||
|
cur_date = date_utils.add(
|
||||||
|
cur_date,
|
||||||
|
this.options.step,
|
||||||
|
'hour',
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.dates.push(cur_date);
|
this.dates.push(cur_date);
|
||||||
@ -393,7 +430,6 @@ export default class Gantt {
|
|||||||
this.options.padding +
|
this.options.padding +
|
||||||
(this.options.bar_height + this.options.padding) *
|
(this.options.bar_height + this.options.padding) *
|
||||||
this.tasks.length;
|
this.tasks.length;
|
||||||
|
|
||||||
createSVG('rect', {
|
createSVG('rect', {
|
||||||
x: 0,
|
x: 0,
|
||||||
y: 0,
|
y: 0,
|
||||||
@ -416,7 +452,6 @@ export default class Gantt {
|
|||||||
const row_height = this.options.bar_height + this.options.padding;
|
const row_height = this.options.bar_height + this.options.padding;
|
||||||
|
|
||||||
let row_y = this.options.header_height + this.options.padding / 2;
|
let row_y = this.options.header_height + this.options.padding / 2;
|
||||||
|
|
||||||
for (let _ of this.tasks) {
|
for (let _ of this.tasks) {
|
||||||
createSVG('rect', {
|
createSVG('rect', {
|
||||||
x: 0,
|
x: 0,
|
||||||
@ -597,7 +632,6 @@ export default class Gantt {
|
|||||||
if (this.view_is(VIEW_MODE.MONTH) && date.getMonth() % 3 === 0) {
|
if (this.view_is(VIEW_MODE.MONTH) && date.getMonth() % 3 === 0) {
|
||||||
tick_class += ' thick';
|
tick_class += ' thick';
|
||||||
}
|
}
|
||||||
|
|
||||||
createSVG('path', {
|
createSVG('path', {
|
||||||
d: `M ${tick_x} ${tick_y} v ${tick_height}`,
|
d: `M ${tick_x} ${tick_y} v ${tick_height}`,
|
||||||
class: tick_class,
|
class: tick_class,
|
||||||
@ -745,6 +779,7 @@ export default class Gantt {
|
|||||||
classes: 'lower-text',
|
classes: 'lower-text',
|
||||||
append_to: this.$lower_header,
|
append_to: this.$lower_header,
|
||||||
});
|
});
|
||||||
|
|
||||||
$lower_text.innerText = date.lower_text;
|
$lower_text.innerText = date.lower_text;
|
||||||
$lower_text.style.left =
|
$lower_text.style.left =
|
||||||
+$lower_text.style.left.slice(0, -2) + 'px';
|
+$lower_text.style.left.slice(0, -2) + 'px';
|
||||||
@ -777,70 +812,104 @@ export default class Gantt {
|
|||||||
}
|
}
|
||||||
|
|
||||||
get_date_info(date, last_date_info) {
|
get_date_info(date, last_date_info) {
|
||||||
|
|
||||||
let last_date = last_date_info
|
let last_date = last_date_info
|
||||||
? last_date_info.date
|
? last_date_info.date
|
||||||
: date_utils.add(date, 1, 'day');
|
: date_utils.add(date, 1, 'day');
|
||||||
const date_text = {
|
let date_text = {}
|
||||||
Hour_lower: date_utils.format(date, 'HH', this.options.language),
|
const custom_mode = this.options.custom_mode
|
||||||
'Quarter Day_lower': date_utils.format(
|
if (custom_mode) {
|
||||||
date,
|
let lower_text,upper_text
|
||||||
'HH',
|
const unit = custom_mode ? custom_mode.unit.toLowerCase() : 'day';
|
||||||
this.options.language,
|
if (unit === 'hour') {
|
||||||
),
|
lower_text = date_utils.format(date, 'HH', this.options.language);
|
||||||
'Half Day_lower': date_utils.format(
|
upper_text = date.getDate() !== last_date.getDate()
|
||||||
date,
|
|
||||||
'HH',
|
|
||||||
this.options.language,
|
|
||||||
),
|
|
||||||
Day_lower:
|
|
||||||
date.getDate() !== last_date.getDate()
|
|
||||||
? date_utils.format(date, 'D', this.options.language)
|
|
||||||
: '',
|
|
||||||
Week_lower:
|
|
||||||
date.getMonth() !== last_date.getMonth()
|
|
||||||
? date_utils.format(date, 'D MMM', this.options.language)
|
|
||||||
: date_utils.format(date, 'D', this.options.language),
|
|
||||||
Month_lower: date_utils.format(date, 'MMMM', this.options.language),
|
|
||||||
Year_lower: date_utils.format(date, 'YYYY', this.options.language),
|
|
||||||
Hour_upper:
|
|
||||||
date.getDate() !== last_date.getDate()
|
|
||||||
? date_utils.format(date, 'D MMMM', this.options.language)
|
? date_utils.format(date, 'D MMMM', this.options.language)
|
||||||
: '',
|
: '';
|
||||||
'Quarter Day_upper':
|
} else if (unit === 'day') {
|
||||||
date.getDate() !== last_date.getDate()
|
lower_text = date.getDate() !== last_date.getDate()
|
||||||
? date_utils.format(date, 'D MMM', this.options.language)
|
? date_utils.format(date, 'D', this.options.language)
|
||||||
: '',
|
: '';
|
||||||
'Half Day_upper':
|
upper_text = date.getMonth() !== last_date.getMonth() || !last_date_info
|
||||||
date.getDate() !== last_date.getDate()
|
|
||||||
? date.getMonth() !== last_date.getMonth()
|
|
||||||
? date_utils.format(
|
|
||||||
date,
|
|
||||||
'D MMM',
|
|
||||||
this.options.language,
|
|
||||||
)
|
|
||||||
: date_utils.format(date, 'D', this.options.language)
|
|
||||||
: '',
|
|
||||||
Day_upper:
|
|
||||||
date.getMonth() !== last_date.getMonth() || !last_date_info
|
|
||||||
? date_utils.format(date, 'MMMM', this.options.language)
|
? date_utils.format(date, 'MMMM', this.options.language)
|
||||||
: '',
|
: '';
|
||||||
Week_upper:
|
} else if (unit === 'month') {
|
||||||
date.getMonth() !== last_date.getMonth()
|
lower_text = date_utils.format(date, 'MMMM', this.options.language);
|
||||||
? date_utils.format(date, 'MMMM', this.options.language)
|
upper_text = date.getFullYear() !== last_date.getFullYear()
|
||||||
: '',
|
|
||||||
Month_upper:
|
|
||||||
date.getFullYear() !== last_date.getFullYear()
|
|
||||||
? date_utils.format(date, 'YYYY', this.options.language)
|
? date_utils.format(date, 'YYYY', this.options.language)
|
||||||
: '',
|
: '';
|
||||||
Year_upper:
|
} else {
|
||||||
date.getFullYear() !== last_date.getFullYear()
|
lower_text = date_utils.format(date, 'YYYY', this.options.language);
|
||||||
? date_utils.format(date, 'YYYY', this.options.language)
|
upper_text = ''; // Default to no upper text for very large units
|
||||||
: '',
|
}
|
||||||
};
|
date_text[`${custom_mode.name}_upper`] = upper_text
|
||||||
let column_width = this.view_is(VIEW_MODE.MONTH)
|
date_text[`${custom_mode.name}_lower`] = lower_text
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
date_text = {
|
||||||
|
Hour_lower: date_utils.format(date, 'HH', this.options.language),
|
||||||
|
'Quarter Day_lower': date_utils.format(
|
||||||
|
date,
|
||||||
|
'HH',
|
||||||
|
this.options.language,
|
||||||
|
),
|
||||||
|
'Half Day_lower': date_utils.format(
|
||||||
|
date,
|
||||||
|
'HH',
|
||||||
|
this.options.language,
|
||||||
|
),
|
||||||
|
Day_lower:
|
||||||
|
date.getDate() !== last_date.getDate()
|
||||||
|
? date_utils.format(date, 'D', this.options.language)
|
||||||
|
: '',
|
||||||
|
Week_lower:
|
||||||
|
date.getMonth() !== last_date.getMonth()
|
||||||
|
? date_utils.format(date, 'D MMM', this.options.language)
|
||||||
|
: date_utils.format(date, 'D', this.options.language),
|
||||||
|
Month_lower: date_utils.format(date, 'MMMM', this.options.language),
|
||||||
|
Year_lower: date_utils.format(date, 'YYYY', this.options.language),
|
||||||
|
Hour_upper:
|
||||||
|
date.getDate() !== last_date.getDate()
|
||||||
|
? date_utils.format(date, 'D MMMM', this.options.language)
|
||||||
|
: '',
|
||||||
|
'Quarter Day_upper':
|
||||||
|
date.getDate() !== last_date.getDate()
|
||||||
|
? date_utils.format(date, 'D MMM', this.options.language)
|
||||||
|
: '',
|
||||||
|
'Half Day_upper':
|
||||||
|
date.getDate() !== last_date.getDate()
|
||||||
|
? date.getMonth() !== last_date.getMonth()
|
||||||
|
? date_utils.format(
|
||||||
|
date,
|
||||||
|
'D MMM',
|
||||||
|
this.options.language,
|
||||||
|
)
|
||||||
|
: date_utils.format(date, 'D', this.options.language)
|
||||||
|
: '',
|
||||||
|
Day_upper:
|
||||||
|
date.getMonth() !== last_date.getMonth() || !last_date_info
|
||||||
|
? date_utils.format(date, 'MMMM', this.options.language)
|
||||||
|
: '',
|
||||||
|
Week_upper:
|
||||||
|
date.getMonth() !== last_date.getMonth()
|
||||||
|
? date_utils.format(date, 'MMMM', this.options.language)
|
||||||
|
: '',
|
||||||
|
Month_upper:
|
||||||
|
date.getFullYear() !== last_date.getFullYear()
|
||||||
|
? date_utils.format(date, 'YYYY', this.options.language)
|
||||||
|
: '',
|
||||||
|
Year_upper:
|
||||||
|
date.getFullYear() !== last_date.getFullYear()
|
||||||
|
? date_utils.format(date, 'YYYY', this.options.language)
|
||||||
|
: '',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
let column_width = custom_mode && custom_mode.lower_text && custom_mode.lower_text.column_width ? custom_mode.lower_text.column_width * (custom_mode.step ?? 1) : this.view_is(VIEW_MODE.MONTH)
|
||||||
? (date_utils.get_days_in_month(date) * this.options.column_width) /
|
? (date_utils.get_days_in_month(date) * this.options.column_width) /
|
||||||
30
|
30
|
||||||
: this.options.column_width;
|
: this.options.column_width;
|
||||||
|
|
||||||
const base_pos = {
|
const base_pos = {
|
||||||
x: last_date_info
|
x: last_date_info
|
||||||
? last_date_info.base_pos_x + last_date_info.column_width
|
? last_date_info.base_pos_x + last_date_info.column_width
|
||||||
@ -864,6 +933,10 @@ export default class Gantt {
|
|||||||
Year_lower: column_width / 2,
|
Year_lower: column_width / 2,
|
||||||
Year_upper: (column_width * 30) / 2,
|
Year_upper: (column_width * 30) / 2,
|
||||||
};
|
};
|
||||||
|
if (custom_mode){
|
||||||
|
x_pos[`${custom_mode.name}_upper`] = column_width / 2
|
||||||
|
x_pos[`${custom_mode.name}_lower`] = column_width / (custom_mode.unit.toLowerCase() === 'day' ? 1 : 2)
|
||||||
|
}
|
||||||
return {
|
return {
|
||||||
date,
|
date,
|
||||||
formatted_date: date_utils.format(date).replaceAll(' ', '_'),
|
formatted_date: date_utils.format(date).replaceAll(' ', '_'),
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user