fix: bugs in view mode renderings
This commit is contained in:
parent
539482e6d9
commit
a7d38841b3
@ -159,9 +159,7 @@ export default class Bar {
|
|||||||
let $date_highlight = document.createElement('div');
|
let $date_highlight = document.createElement('div');
|
||||||
$date_highlight.classList.add('date-highlight');
|
$date_highlight.classList.add('date-highlight');
|
||||||
$date_highlight.classList.add(`highlight-${this.task.id}`);
|
$date_highlight.classList.add(`highlight-${this.task.id}`);
|
||||||
// $date_highlight.style.height = this.height * 0.8 + 'px';
|
|
||||||
$date_highlight.style.width = this.width + 'px';
|
$date_highlight.style.width = this.width + 'px';
|
||||||
// $date_highlight.style.top = this.gantt.config.header_height - 25 + 'px';
|
|
||||||
$date_highlight.style.left = x + 'px';
|
$date_highlight.style.left = x + 'px';
|
||||||
this.$date_highlight = $date_highlight;
|
this.$date_highlight = $date_highlight;
|
||||||
this.gantt.$lower_header.prepend($date_highlight);
|
this.gantt.$lower_header.prepend($date_highlight);
|
||||||
|
|||||||
@ -1,10 +1,16 @@
|
|||||||
import date_utils from './date_utils';
|
import date_utils from './date_utils';
|
||||||
|
|
||||||
|
function getDecade(d) {
|
||||||
|
const year = d.getFullYear();
|
||||||
|
return year - (year % 10) + '';
|
||||||
|
}
|
||||||
|
|
||||||
const DEFAULT_VIEW_MODES = [
|
const DEFAULT_VIEW_MODES = [
|
||||||
{
|
{
|
||||||
name: 'Hour',
|
name: 'Hour',
|
||||||
padding: '7d',
|
padding: '7d',
|
||||||
step: '1h',
|
step: '1h',
|
||||||
|
format_string: 'YYYY-MM-DD HH',
|
||||||
lower_text: 'HH',
|
lower_text: 'HH',
|
||||||
upper_text: (d, ld, lang) =>
|
upper_text: (d, ld, lang) =>
|
||||||
!ld || d.getDate() !== ld.getDate()
|
!ld || d.getDate() !== ld.getDate()
|
||||||
@ -57,9 +63,10 @@ const DEFAULT_VIEW_MODES = [
|
|||||||
name: 'Week',
|
name: 'Week',
|
||||||
padding: '1m',
|
padding: '1m',
|
||||||
step: '7d',
|
step: '7d',
|
||||||
|
format_string: 'YYYY-MM-DD',
|
||||||
column_width: 140,
|
column_width: 140,
|
||||||
lower_text: (d, ld, lang) =>
|
lower_text: (d, ld, lang) =>
|
||||||
d.getMonth() !== ld.getMonth()
|
!ld || d.getMonth() !== ld.getMonth()
|
||||||
? date_utils.format(d, 'D MMM', lang)
|
? date_utils.format(d, 'D MMM', lang)
|
||||||
: date_utils.format(d, 'D', lang),
|
: date_utils.format(d, 'D', lang),
|
||||||
upper_text: (d, ld, lang) =>
|
upper_text: (d, ld, lang) =>
|
||||||
@ -89,7 +96,9 @@ const DEFAULT_VIEW_MODES = [
|
|||||||
step: '1y',
|
step: '1y',
|
||||||
column_width: 120,
|
column_width: 120,
|
||||||
format_string: 'YYYY',
|
format_string: 'YYYY',
|
||||||
upper_text: 'YYYY',
|
upper_text: (d, ld, lang) =>
|
||||||
|
!ld || getDecade(d) !== getDecade(ld) ? getDecade(d) : '',
|
||||||
|
lower_text: 'YYYY',
|
||||||
default_snap: '30d',
|
default_snap: '30d',
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
@ -102,9 +111,11 @@ const DEFAULT_OPTIONS = {
|
|||||||
container_height: 300,
|
container_height: 300,
|
||||||
column_width: null,
|
column_width: null,
|
||||||
date_format: 'YYYY-MM-DD',
|
date_format: 'YYYY-MM-DD',
|
||||||
|
upper_header_height: 45,
|
||||||
|
lower_header_height: 30,
|
||||||
snap_at: null,
|
snap_at: null,
|
||||||
infinite_padding: true,
|
infinite_padding: false,
|
||||||
holidays: { '#fff7ed': 'weekend' },
|
holidays: { 'var(--g-weekend-highlight-color)': 'weekend' },
|
||||||
ignore: [],
|
ignore: [],
|
||||||
language: 'en',
|
language: 'en',
|
||||||
lines: 'both',
|
lines: 'both',
|
||||||
|
|||||||
119
src/index.js
119
src/index.js
@ -78,6 +78,8 @@ export default class Gantt {
|
|||||||
const CSS_VARIABLES = {
|
const CSS_VARIABLES = {
|
||||||
'grid-height': 'container_height',
|
'grid-height': 'container_height',
|
||||||
'bar-height': 'bar_height',
|
'bar-height': 'bar_height',
|
||||||
|
'lower-header-height': 'lower_header_height',
|
||||||
|
'upper-header-height': 'upper_header_height',
|
||||||
};
|
};
|
||||||
|
|
||||||
for (let name in CSS_VARIABLES) {
|
for (let name in CSS_VARIABLES) {
|
||||||
@ -240,7 +242,10 @@ export default class Gantt {
|
|||||||
'--gv-column-width',
|
'--gv-column-width',
|
||||||
this.config.column_width + 'px',
|
this.config.column_width + 'px',
|
||||||
);
|
);
|
||||||
this.config.header_height = this.config.column_width * 2.5;
|
this.config.header_height =
|
||||||
|
this.options.lower_header_height +
|
||||||
|
this.options.upper_header_height +
|
||||||
|
10;
|
||||||
}
|
}
|
||||||
|
|
||||||
setup_dates() {
|
setup_dates() {
|
||||||
@ -643,14 +648,47 @@ 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.
|
* @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.
|
||||||
*/
|
*/
|
||||||
highlightToday() {
|
highlightNow() {
|
||||||
const today = new Date();
|
let now = new Date();
|
||||||
if (today < this.gantt_start || today > this.gantt_end) return null;
|
if (now < this.gantt_start || now > this.gantt_end) return null;
|
||||||
|
|
||||||
|
let current = new Date(),
|
||||||
|
el = this.$container.querySelector(
|
||||||
|
'.date_' +
|
||||||
|
sanitize(
|
||||||
|
date_utils.format(
|
||||||
|
current,
|
||||||
|
this.config.view_mode.format_string,
|
||||||
|
this.options.language,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
// safety check to prevent infinite loop
|
||||||
|
let c = 0;
|
||||||
|
while (!el && c < this.config.step) {
|
||||||
|
current = date_utils.add(current, -1, this.config.unit);
|
||||||
|
el = this.$container.querySelector(
|
||||||
|
'.date_' +
|
||||||
|
sanitize(
|
||||||
|
date_utils.format(
|
||||||
|
current,
|
||||||
|
this.config.view_mode.format_string,
|
||||||
|
this.options.language,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
c++;
|
||||||
|
}
|
||||||
|
|
||||||
|
el.classList.add('current-date-highlight');
|
||||||
|
|
||||||
const diff_in_units = date_utils.diff(
|
const diff_in_units = date_utils.diff(
|
||||||
today,
|
now,
|
||||||
this.gantt_start,
|
this.gantt_start,
|
||||||
this.config.unit,
|
this.config.unit,
|
||||||
);
|
);
|
||||||
|
|
||||||
const left =
|
const left =
|
||||||
(diff_in_units / this.config.step) * this.config.column_width;
|
(diff_in_units / this.config.step) * this.config.column_width;
|
||||||
const height =
|
const height =
|
||||||
@ -658,11 +696,6 @@ export default class Gantt {
|
|||||||
this.tasks.length +
|
this.tasks.length +
|
||||||
20 +
|
20 +
|
||||||
this.options.padding / 2;
|
this.options.padding / 2;
|
||||||
const date = date_utils.format(
|
|
||||||
today,
|
|
||||||
this.config.view_mode.format_string,
|
|
||||||
this.options.language,
|
|
||||||
);
|
|
||||||
|
|
||||||
this.$current_highlight = this.create_el({
|
this.$current_highlight = this.create_el({
|
||||||
top: this.config.header_height - 20,
|
top: this.config.header_height - 20,
|
||||||
@ -671,10 +704,6 @@ export default class Gantt {
|
|||||||
classes: 'current-highlight',
|
classes: 'current-highlight',
|
||||||
append_to: this.$extras,
|
append_to: this.$extras,
|
||||||
});
|
});
|
||||||
|
|
||||||
let $today = this.$container
|
|
||||||
.querySelector('.date_' + date.replaceAll(' ', '_'))
|
|
||||||
.classList.add('current-date-highlight');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
make_grid_highlights() {
|
make_grid_highlights() {
|
||||||
@ -722,7 +751,7 @@ export default class Gantt {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const highlightDimensions = this.highlightToday(this.config.view_mode);
|
const highlightDimensions = this.highlightNow(this.config.view_mode);
|
||||||
|
|
||||||
if (!highlightDimensions) return;
|
if (!highlightDimensions) return;
|
||||||
}
|
}
|
||||||
@ -742,16 +771,18 @@ export default class Gantt {
|
|||||||
make_dates() {
|
make_dates() {
|
||||||
this.upper_texts_x = {};
|
this.upper_texts_x = {};
|
||||||
this.get_dates_to_draw().forEach((date, i) => {
|
this.get_dates_to_draw().forEach((date, i) => {
|
||||||
let $lower_text = this.create_el({
|
if (date.lower_text) {
|
||||||
left: date.lower_x,
|
let $lower_text = this.create_el({
|
||||||
top: date.lower_y,
|
left: date.lower_x,
|
||||||
classes: 'lower-text date_' + date.formatted_date,
|
top: date.lower_y,
|
||||||
append_to: this.$lower_header,
|
classes: 'lower-text date_' + sanitize(date.formatted_date),
|
||||||
});
|
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';
|
||||||
|
}
|
||||||
|
|
||||||
if (date.upper_text) {
|
if (date.upper_text) {
|
||||||
this.upper_texts_x[date.upper_text] = date.upper_x;
|
this.upper_texts_x[date.upper_text] = date.upper_x;
|
||||||
@ -785,13 +816,9 @@ export default class Gantt {
|
|||||||
|
|
||||||
let column_width = this.config.column_width;
|
let column_width = this.config.column_width;
|
||||||
|
|
||||||
const base_pos = {
|
const base_x = last_date_info
|
||||||
x: last_date_info
|
? last_date_info.base_x + last_date_info.column_width
|
||||||
? last_date_info.base_pos_x + last_date_info.column_width
|
: 0;
|
||||||
: 0,
|
|
||||||
lower_y: this.config.column_width * 1.5,
|
|
||||||
upper_y: 15,
|
|
||||||
};
|
|
||||||
|
|
||||||
let upper_text = this.config.view_mode.upper_text;
|
let upper_text = this.config.view_mode.upper_text;
|
||||||
let lower_text = this.config.view_mode.lower_text;
|
let lower_text = this.config.view_mode.lower_text;
|
||||||
@ -812,11 +839,11 @@ export default class Gantt {
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
date,
|
date,
|
||||||
formatted_date: date_utils
|
formatted_date: sanitize(
|
||||||
.format(date, this.config.view_mode.format_string)
|
date_utils.format(date, this.config.view_mode.format_string),
|
||||||
.replaceAll(' ', '_'),
|
),
|
||||||
column_width: this.config.column_width,
|
column_width: this.config.column_width,
|
||||||
base_pos_x: base_pos.x,
|
base_x,
|
||||||
upper_text: this.config.view_mode.upper_text(
|
upper_text: this.config.view_mode.upper_text(
|
||||||
date,
|
date,
|
||||||
last_date,
|
last_date,
|
||||||
@ -828,13 +855,13 @@ export default class Gantt {
|
|||||||
this.options.language,
|
this.options.language,
|
||||||
),
|
),
|
||||||
upper_x:
|
upper_x:
|
||||||
base_pos.x +
|
base_x +
|
||||||
(column_width * this.config.view_mode.upper_text_frequency ||
|
(column_width * this.config.view_mode.upper_text_frequency ||
|
||||||
1) /
|
1) /
|
||||||
2,
|
2,
|
||||||
upper_y: base_pos.upper_y,
|
upper_y: 15,
|
||||||
lower_x: base_pos.x,
|
lower_x: base_x,
|
||||||
lower_y: base_pos.lower_y,
|
lower_y: this.options.upper_header_height + 5,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -924,6 +951,7 @@ export default class Gantt {
|
|||||||
this.$container.scrollLeft / this.config.column_width,
|
this.$container.scrollLeft / this.config.column_width,
|
||||||
this.config.unit,
|
this.config.unit,
|
||||||
);
|
);
|
||||||
|
|
||||||
let current_upper = this.config.view_mode.upper_text(this.current_date);
|
let current_upper = this.config.view_mode.upper_text(this.current_date);
|
||||||
let $el = this.upperTexts.find(
|
let $el = this.upperTexts.find(
|
||||||
(el) => el.textContent === current_upper,
|
(el) => el.textContent === current_upper,
|
||||||
@ -1094,9 +1122,11 @@ export default class Gantt {
|
|||||||
// Calculate current scroll position's upper text
|
// Calculate current scroll position's upper text
|
||||||
this.current_date = date_utils.add(
|
this.current_date = date_utils.add(
|
||||||
this.gantt_start,
|
this.gantt_start,
|
||||||
e.currentTarget.scrollLeft / this.config.column_width,
|
(e.currentTarget.scrollLeft / this.config.column_width) *
|
||||||
|
this.config.step,
|
||||||
this.config.unit,
|
this.config.unit,
|
||||||
);
|
);
|
||||||
|
|
||||||
let current_upper = this.config.view_mode.upper_text(
|
let current_upper = this.config.view_mode.upper_text(
|
||||||
this.current_date,
|
this.current_date,
|
||||||
);
|
);
|
||||||
@ -1107,8 +1137,9 @@ export default class Gantt {
|
|||||||
// Recalculate for smoother experience
|
// Recalculate for smoother experience
|
||||||
this.current_date = date_utils.add(
|
this.current_date = date_utils.add(
|
||||||
this.gantt_start,
|
this.gantt_start,
|
||||||
(e.currentTarget.scrollLeft + $el.clientWidth) /
|
((e.currentTarget.scrollLeft + $el.clientWidth) /
|
||||||
this.config.column_width,
|
this.config.column_width) *
|
||||||
|
this.config.step,
|
||||||
this.config.unit,
|
this.config.unit,
|
||||||
);
|
);
|
||||||
current_upper = this.config.view_mode.upper_text(this.current_date);
|
current_upper = this.config.view_mode.upper_text(this.current_date);
|
||||||
@ -1436,3 +1467,7 @@ Gantt.VIEW_MODE = {
|
|||||||
function generate_id(task) {
|
function generate_id(task) {
|
||||||
return task.name + '_' + Math.random().toString(36).slice(2, 12);
|
return task.name + '_' + Math.random().toString(36).slice(2, 12);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function sanitize(s) {
|
||||||
|
return s.replaceAll(' ', '_').replaceAll(':', '_').replaceAll('.', '_');
|
||||||
|
}
|
||||||
|
|||||||
@ -53,18 +53,18 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
& .upper-header {
|
& .upper-header {
|
||||||
height: calc(var(--gv-column-width) * 1.5);
|
height: var(--gv-upper-header-height);
|
||||||
}
|
}
|
||||||
|
|
||||||
& .lower-header {
|
& .lower-header {
|
||||||
height: var(--gv-column-width);
|
height: var(--gv-lower-header-height);
|
||||||
}
|
}
|
||||||
|
|
||||||
& .lower-text {
|
& .lower-text {
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
width: calc(var(--gv-column-width) * 0.8);
|
width: calc(var(--gv-column-width) * 0.8);
|
||||||
height: calc(var(--gv-column-width) * 0.8);
|
height: calc(var(--gv-lower-header-height) * 0.8);
|
||||||
margin: 0 calc(var(--gv-column-width) * 0.1);
|
margin: 0 calc(var(--gv-column-width) * 0.1);
|
||||||
align-content: center;
|
align-content: center;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
@ -77,13 +77,13 @@
|
|||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
color: var(--g-text-dark);
|
color: var(--g-text-dark);
|
||||||
|
height: calc(var(--gv-lower-header-height) * 0.66);
|
||||||
}
|
}
|
||||||
|
|
||||||
& .current-upper {
|
& .current-upper {
|
||||||
position: sticky;
|
position: sticky;
|
||||||
left: 0 !important;
|
left: 0 !important;
|
||||||
padding: 0 10px;
|
padding: 0 calc(var(--gv-lower-header-height) * 0.33);
|
||||||
height: 20px;
|
|
||||||
background: white;
|
background: white;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -128,9 +128,11 @@
|
|||||||
|
|
||||||
& .date-highlight {
|
& .date-highlight {
|
||||||
background-color: var(--g-progress-color);
|
background-color: var(--g-progress-color);
|
||||||
border-radius: 12px;
|
border-radius: 20px;
|
||||||
height: calc(var(--gv-bar-height) * 0.8);
|
height: var(--gv-lower-header-height);
|
||||||
top: calc(var(--gv-column-width) * 1.5);
|
top: calc(
|
||||||
|
var(--gv-upper-header-height) + var(--gv-lower-header-height) * 0.1
|
||||||
|
);
|
||||||
position: absolute;
|
position: absolute;
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
@ -145,7 +147,7 @@
|
|||||||
& .current-date-highlight {
|
& .current-date-highlight {
|
||||||
background: var(--g-blue-dark);
|
background: var(--g-blue-dark);
|
||||||
color: var(--g-text-light);
|
color: var(--g-text-light);
|
||||||
border-radius: 100px;
|
border-radius: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
& .holiday-label {
|
& .holiday-label {
|
||||||
|
|||||||
@ -20,4 +20,5 @@
|
|||||||
--g-blue-dark: #2c94ec;
|
--g-blue-dark: #2c94ec;
|
||||||
--g-header-background: #ffffff;
|
--g-header-background: #ffffff;
|
||||||
--g-row-color: #fff;
|
--g-row-color: #fff;
|
||||||
|
--g-weekend-highlight-color: #bfdbfe;
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user