chore: format

This commit is contained in:
Safwan Samsudeen 2024-04-30 05:06:17 +05:30
parent 1403f2e581
commit 3194f883ad
20 changed files with 5390 additions and 5126 deletions

View File

@ -51,18 +51,18 @@ var gantt = new Gantt("#gantt", tasks);
You can also pass various options to the Gantt constructor:
```js
var gantt = new Gantt("#gantt", tasks, {
var gantt = new Gantt('#gantt', tasks, {
header_height: 50,
column_width: 30,
step: 24,
view_modes: ["Quarter Day", "Half Day", "Day", "Week", "Month"],
view_modes: ['Quarter Day', 'Half Day', 'Day', 'Week', 'Month'],
bar_height: 20,
bar_corner_radius: 3,
arrow_curve: 5,
padding: 18,
view_mode: "Day",
date_format: "YYYY-MM-DD",
language: "en", // or 'es', 'it', 'ru', 'ptBr', 'fr', 'tr', 'zh', 'de', 'hu'
view_mode: 'Day',
date_format: 'YYYY-MM-DD',
language: 'en', // or 'es', 'it', 'ru', 'ptBr', 'fr', 'tr', 'zh', 'de', 'hu'
custom_popup_html: null,
});
```

16
dist/frappe-gantt.css vendored
View File

@ -111,7 +111,7 @@
}
.gantt-container .today-button,
.gantt-container .viewmode-select {
background: #F4F5F6;
background: #f4f5f6;
text-align: -webkit-center;
text-align: center;
height: 25px;
@ -132,7 +132,7 @@
text-overflow: "";
}
.gantt-container .date-highlight {
background-color: #EBEEF0;
background-color: #ebeef0;
border-radius: 12px;
position: absolute;
display: none;
@ -164,7 +164,7 @@
stroke: #ebeff2;
}
.gantt .tick {
stroke: #EBEEF0;
stroke: #ebeef0;
stroke-width: 0.4;
}
.gantt .tick.thick {
@ -172,11 +172,11 @@
stroke-width: 0.7;
}
.gantt .holiday-highlight {
fill: #F9FAFA;
fill: #f9fafa;
}
.gantt .arrow {
fill: none;
stroke: #9FA9B1;
stroke: #9fa9b1;
stroke-width: 1;
}
.gantt .bar-wrapper .bar {
@ -186,7 +186,7 @@
transition: stroke-width 0.3s ease;
}
.gantt .bar-progress {
fill: #EBEEF0;
fill: #ebeef0;
}
.gantt .bar-expected-progress {
fill: #c4c4e9;
@ -269,7 +269,7 @@
position: absolute;
top: 0;
left: 0;
background: #171B1F;
background: #171b1f;
padding: 10px;
border-radius: 5px;
width: max-content;
@ -284,7 +284,7 @@
color: #fff;
}
.gantt-container .popup-wrapper .subtitle {
color: #98A1A9;
color: #98a1a9;
}
.gantt-container .popup-wrapper .pointer {
position: absolute;

875
dist/frappe-gantt.js vendored

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -28,7 +28,9 @@
</head>
<body>
<div class="container">
<h2 class="heading">Interactive Gantt Chart entirely made in SVG!</h2>
<h2 class="heading">
Interactive Gantt Chart entirely made in SVG!
</h2>
<div class="gantt-target"></div>
</div>
<script>
@ -37,39 +39,39 @@
start: '2024-04-01',
end: '2024-04-01',
name: 'Redesign website',
id: "Task 0",
progress: 30
id: 'Task 0',
progress: 30,
},
{
start: '2024-03-26',
// Utilizes duration
duration: '6d',
name: 'Write new content',
id: "Task 1",
id: 'Task 1',
progress: 5,
important: true
important: true,
},
{
start: '2024-04-04',
end: '2024-04-08',
name: 'Apply new styles',
id: "Task 2",
id: 'Task 2',
progress: 80,
dependencies: 'Task 1'
dependencies: 'Task 1',
},
{
start: '2024-04-08',
end: '2024-04-09',
name: 'Review',
id: "Task 3",
id: 'Task 3',
progress: 5,
dependencies: 'Task 2'
dependencies: 'Task 2',
},
{
start: '2024-04-08',
end: '2024-04-10',
name: 'Deploy',
id: "Task 4",
id: 'Task 4',
progress: 0,
// dependencies: 'Task 2'
},
@ -77,10 +79,10 @@
start: '2024-04-21',
end: '2024-04-29',
name: 'Go Live!',
id: "Task 5",
id: 'Task 5',
progress: 0,
dependencies: 'Task 2',
custom_class: 'bar-milestone'
custom_class: 'bar-milestone',
},
// {
// start: '2014-01-05',
@ -92,11 +94,17 @@
];
// Uncomment to test fixed header
tasks = [...tasks, ...Array.from({length: tasks.length * 3}, (_, i) => ({...tasks[i % 3], id: i}))]
tasks = [
...tasks,
...Array.from({ length: tasks.length * 3 }, (_, i) => ({
...tasks[i % 3],
id: i,
})),
];
let gantt_chart = new Gantt(".gantt-target", tasks, {
let gantt_chart = new Gantt('.gantt-target', tasks, {
on_click: (task) => {
console.log("Click", task);
console.log('Click', task);
},
// on_double_click: (task) => {
// console.log("Double Click", task);
@ -113,8 +121,8 @@
// on_hover: (task, x, y) => {
// console.log("Hover", x, y);
// },
view_mode: "Day",
view_mode_padding: { DAY: "3d" },
view_mode: 'Day',
view_mode_padding: { DAY: '3d' },
popup: false,
// scroll_to: 'today',
// view_mode_select: true,

View File

@ -1,13 +1,13 @@
import sass from "rollup-plugin-sass";
import { terser } from "rollup-plugin-terser";
import sass from 'rollup-plugin-sass';
import { terser } from 'rollup-plugin-terser';
const dev = {
input: "src/index.js",
input: 'src/index.js',
output: {
name: "Gantt",
file: "dist/frappe-gantt.js",
name: 'Gantt',
file: 'dist/frappe-gantt.js',
sourcemap: true,
format: "iife",
format: 'iife',
},
plugins: [
sass({
@ -16,18 +16,18 @@ const dev = {
],
};
const prod = {
input: "src/index.js",
input: 'src/index.js',
output: {
name: "Gantt",
file: "dist/frappe-gantt.min.js",
name: 'Gantt',
file: 'dist/frappe-gantt.min.js',
sourcemap: true,
format: "iife",
format: 'iife',
},
plugins: [
sass({
output: true,
options: {
outputStyle: "compressed",
outputStyle: 'compressed',
},
}),
terser(),

View File

@ -1,4 +1,4 @@
import { createSVG } from "./svg_utils";
import { createSVG } from './svg_utils';
export default class Arrow {
constructor(gantt, from_task, to_task) {
@ -29,7 +29,8 @@ export default class Arrow {
this.from_task.task._index +
this.gantt.options.padding;
const end_x = this.to_task.$bar.getX() - this.gantt.options.padding / 2 - 7;
const end_x =
this.to_task.$bar.getX() - this.gantt.options.padding / 2 - 7;
const end_y =
this.gantt.options.header_height +
this.gantt.options.bar_height / 2 +
@ -61,7 +62,9 @@ export default class Arrow {
) {
const down_1 = this.gantt.options.padding / 2 - curve;
const down_2 =
this.to_task.$bar.getY() + this.to_task.$bar.getHeight() / 2 - curve_y;
this.to_task.$bar.getY() +
this.to_task.$bar.getHeight() / 2 -
curve_y;
const left = this.to_task.$bar.getX() - this.gantt.options.padding;
this.path = `
@ -80,15 +83,15 @@ export default class Arrow {
}
draw() {
this.element = createSVG("path", {
this.element = createSVG('path', {
d: this.path,
"data-from": this.from_task.task.id,
"data-to": this.to_task.task.id,
'data-from': this.from_task.task.id,
'data-to': this.to_task.task.id,
});
}
update() {
this.calculate_path();
this.element.setAttribute("d", this.path);
this.element.setAttribute('d', this.path);
}
}

View File

@ -1,5 +1,5 @@
import date_utils from "./date_utils";
import { $, createSVG, animateSVG } from "./svg_utils";
import date_utils from './date_utils';
import { $, createSVG, animateSVG } from './svg_utils';
export default class Bar {
constructor(gantt, task) {
@ -33,32 +33,35 @@ export default class Bar {
this.gantt.options.column_width *
this.duration *
(this.task.progress / 100) || 0;
this.group = createSVG("g", {
class: "bar-wrapper" + (this.task.custom_class ? " " + this.task.custom_class : "") + (this.task.important ? ' important' : ''),
"data-id": this.task.id,
this.group = createSVG('g', {
class:
'bar-wrapper' +
(this.task.custom_class ? ' ' + this.task.custom_class : '') +
(this.task.important ? ' important' : ''),
'data-id': this.task.id,
});
this.bar_group = createSVG("g", {
class: "bar-group",
this.bar_group = createSVG('g', {
class: 'bar-group',
append_to: this.group,
});
this.handle_group = createSVG("g", {
class: "handle-group",
this.handle_group = createSVG('g', {
class: 'handle-group',
append_to: this.group,
});
}
prepare_helpers() {
SVGElement.prototype.getX = function () {
return +this.getAttribute("x");
return +this.getAttribute('x');
};
SVGElement.prototype.getY = function () {
return +this.getAttribute("y");
return +this.getAttribute('y');
};
SVGElement.prototype.getWidth = function () {
return +this.getAttribute("width");
return +this.getAttribute('width');
};
SVGElement.prototype.getHeight = function () {
return +this.getAttribute("height");
return +this.getAttribute('height');
};
SVGElement.prototype.getEndX = function () {
return this.getX() + this.getWidth();
@ -89,40 +92,40 @@ export default class Bar {
}
draw_bar() {
this.$bar = createSVG("rect", {
this.$bar = createSVG('rect', {
x: this.x,
y: this.y,
width: this.width,
height: this.height,
rx: this.corner_radius,
ry: this.corner_radius,
class: "bar",
class: 'bar',
append_to: this.bar_group,
});
animateSVG(this.$bar, "width", 0, this.width);
animateSVG(this.$bar, 'width', 0, this.width);
if (this.invalid) {
this.$bar.classList.add("bar-invalid");
this.$bar.classList.add('bar-invalid');
}
}
draw_expected_progress_bar() {
if (this.invalid) return;
this.$expected_bar_progress = createSVG("rect", {
this.$expected_bar_progress = createSVG('rect', {
x: this.x,
y: this.y,
width: this.expected_progress_width,
height: this.height,
rx: this.corner_radius,
ry: this.corner_radius,
class: "bar-expected-progress",
class: 'bar-expected-progress',
append_to: this.bar_group,
});
animateSVG(
this.$expected_bar_progress,
"width",
'width',
0,
this.expected_progress_width,
);
@ -130,33 +133,33 @@ export default class Bar {
draw_progress_bar() {
if (this.invalid) return;
this.$bar_progress = createSVG("rect", {
this.$bar_progress = createSVG('rect', {
x: this.x,
y: this.y,
width: this.progress_width,
height: this.height,
rx: this.corner_radius,
ry: this.corner_radius,
class: "bar-progress",
class: 'bar-progress',
append_to: this.bar_group,
});
const x = (date_utils.diff(this.task._start, this.gantt.gantt_start, 'hour') /
const x =
(date_utils.diff(this.task._start, this.gantt.gantt_start, 'hour') /
this.gantt.options.step) *
this.gantt.options.column_width;
let $date_highlight = document.createElement("div");
$date_highlight.id = `${this.task.id}-highlight`
$date_highlight.classList.add('date-highlight')
$date_highlight.style.height = this.height * 0.8 + 'px'
$date_highlight.style.width = this.width + 'px'
$date_highlight.style.top = this.gantt.options.header_height - 25 + 'px'
$date_highlight.style.left = x + 'px'
this.$date_highlight = $date_highlight
this.gantt.$lower_header.prepend($date_highlight)
let $date_highlight = document.createElement('div');
$date_highlight.id = `${this.task.id}-highlight`;
$date_highlight.classList.add('date-highlight');
$date_highlight.style.height = this.height * 0.8 + 'px';
$date_highlight.style.width = this.width + 'px';
$date_highlight.style.top =
this.gantt.options.header_height - 25 + 'px';
$date_highlight.style.left = x + 'px';
this.$date_highlight = $date_highlight;
this.gantt.$lower_header.prepend($date_highlight);
animateSVG(this.$bar_progress, "width", 0, this.progress_width);
animateSVG(this.$bar_progress, 'width', 0, this.progress_width);
}
draw_label() {
@ -166,22 +169,23 @@ export default class Bar {
x_coord = this.x + this.image_size + 5;
}
createSVG("text", {
createSVG('text', {
x: x_coord,
y: this.y + this.height / 2,
innerHTML: this.task.name,
class: "bar-label",
class: 'bar-label',
append_to: this.bar_group,
});
// labels get BBox in the next tick
requestAnimationFrame(() => this.update_label_position());
}
draw_thumbnail() {
let x_offset = 10, y_offset = 2;
let x_offset = 10,
y_offset = 2;
let defs, clipPath;
defs = createSVG('defs', {
append_to: this.bar_group
append_to: this.bar_group,
});
createSVG('rect', {
@ -192,17 +196,17 @@ export default class Bar {
height: this.image_size,
rx: '15',
class: 'img_mask',
append_to: defs
append_to: defs,
});
clipPath = createSVG('clipPath', {
id: 'clip_' + this.task.id,
append_to: defs
append_to: defs,
});
createSVG('use', {
href: '#rect_' + this.task.id,
append_to: clipPath
append_to: clipPath,
});
createSVG('image', {
@ -213,7 +217,7 @@ export default class Bar {
class: 'bar-img',
href: this.task.thumbnail,
clipPath: 'clip_' + this.task.id,
append_to: this.bar_group
append_to: this.bar_group,
});
}
@ -223,31 +227,31 @@ export default class Bar {
const bar = this.$bar;
const handle_width = 8;
createSVG("rect", {
createSVG('rect', {
x: bar.getX() + bar.getWidth() + handle_width - 4,
y: bar.getY() + 1,
width: handle_width,
height: this.height - 2,
rx: this.corner_radius,
ry: this.corner_radius,
class: "handle right",
class: 'handle right',
append_to: this.handle_group,
});
createSVG("rect", {
createSVG('rect', {
x: bar.getX() - handle_width - 4,
y: bar.getY() + 1,
width: handle_width,
height: this.height - 2,
rx: this.corner_radius,
ry: this.corner_radius,
class: "handle left",
class: 'handle left',
append_to: this.handle_group,
});
this.$handle_progress = createSVG("polygon", {
points: this.get_progress_polygon_points().join(","),
class: "handle progress",
this.$handle_progress = createSVG('polygon', {
points: this.get_progress_polygon_points().join(','),
class: 'handle progress',
append_to: this.handle_group,
});
}
@ -262,13 +266,17 @@ export default class Bar {
bar_progress.getY() + bar_progress.getHeight() / 2,
bar_progress.getEndX(),
bar_progress.getY() + bar_progress.getHeight() / 2 - icon_height / 2,
bar_progress.getY() +
bar_progress.getHeight() / 2 -
icon_height / 2,
bar_progress.getEndX() + icon_width / 2,
bar_progress.getY() + bar_progress.getHeight() / 2,
bar_progress.getEndX(),
bar_progress.getY() + bar_progress.getHeight() / 2 + icon_height / 2,
bar_progress.getY() +
bar_progress.getHeight() / 2 +
icon_height / 2,
bar_progress.getEndX() - icon_width / 2,
bar_progress.getY() + bar_progress.getHeight() / 2,
@ -282,34 +290,46 @@ export default class Bar {
setup_click_event() {
let task_id = this.task.id;
$.on(this.group, "mouseover", (e) => {
this.gantt.trigger_event("hover", [this.task, e.screenX, e.screenY, e])
})
let timeout;
$.on(this.group, "mouseenter", (e) => timeout = setTimeout(() => {
this.show_popup(e.offsetX)
document.querySelector(`#${task_id}-highlight`).style.display = 'block'
}, 200))
$.on(this.group, "mouseleave", () => {
clearTimeout(timeout)
this.gantt.popup?.hide?.()
document.querySelector(`#${task_id}-highlight`).style.display = 'none'
})
$.on(this.group, this.gantt.options.popup_trigger, () => {
this.gantt.trigger_event("click", [this.task]);
$.on(this.group, 'mouseover', (e) => {
this.gantt.trigger_event('hover', [
this.task,
e.screenX,
e.screenY,
e,
]);
});
$.on(this.group, "dblclick", (e) => {
let timeout;
$.on(
this.group,
'mouseenter',
(e) =>
(timeout = setTimeout(() => {
this.show_popup(e.offsetX);
document.querySelector(
`#${task_id}-highlight`,
).style.display = 'block';
}, 200)),
);
$.on(this.group, 'mouseleave', () => {
clearTimeout(timeout);
this.gantt.popup?.hide?.();
document.querySelector(`#${task_id}-highlight`).style.display =
'none';
});
$.on(this.group, this.gantt.options.popup_trigger, () => {
this.gantt.trigger_event('click', [this.task]);
});
$.on(this.group, 'dblclick', (e) => {
if (this.action_completed) {
// just finished a move action, wait for a few seconds
return;
}
this.gantt.trigger_event("double_click", [this.task]);
this.gantt.trigger_event('double_click', [this.task]);
});
}
@ -318,12 +338,12 @@ export default class Bar {
const start_date = date_utils.format(
this.task._start,
"MMM D",
'MMM D',
this.gantt.options.language,
);
const end_date = date_utils.format(
date_utils.add(this.task._end, -1, "second"),
"MMM D",
date_utils.add(this.task._end, -1, 'second'),
'MMM D',
this.gantt.options.language,
);
const subtitle = `${start_date} - ${end_date}<br/>Progress: ${this.task.progress}`;
@ -352,12 +372,12 @@ export default class Bar {
width = null;
return;
}
this.update_attr(bar, "x", x);
this.$date_highlight.style.left = x + 'px'
this.update_attr(bar, 'x', x);
this.$date_highlight.style.left = x + 'px';
}
if (width) {
this.update_attr(bar, "width", width);
this.$date_highlight.style.width = width + 'px'
this.update_attr(bar, 'width', width);
this.$date_highlight.style.width = width + 'px';
}
this.update_label_position();
this.update_handle_position();
@ -378,8 +398,8 @@ export default class Bar {
let barWidthLimit = this.$bar.getX() + this.$bar.getWidth();
let newLabelX = label.getX() + x;
let newImgX = img && img.getX() + x || 0;
let imgWidth = img && img.getBBox().width + 7 || 7;
let newImgX = (img && img.getX() + x) || 0;
let imgWidth = (img && img.getBBox().width + 7) || 7;
let labelEndX = newLabelX + label.getBBox().width + 7;
let viewportCentral = sx + container.clientWidth / 2;
@ -391,13 +411,16 @@ export default class Bar {
img.setAttribute('x', newImgX);
img_mask.setAttribute('x', newImgX);
}
} else if ((newLabelX - imgWidth) > this.$bar.getX() && x < 0 && labelEndX > viewportCentral) {
} else if (
newLabelX - imgWidth > this.$bar.getX() &&
x < 0 &&
labelEndX > viewportCentral
) {
label.setAttribute('x', newLabelX);
if (img) {
img.setAttribute('x', newImgX);
img_mask.setAttribute('x', newImgX);
}
}
}
@ -417,17 +440,17 @@ export default class Bar {
if (!changed) return;
this.gantt.trigger_event("date_change", [
this.gantt.trigger_event('date_change', [
this.task,
new_start_date,
date_utils.add(new_end_date, -1, "second"),
date_utils.add(new_end_date, -1, 'second'),
]);
}
progress_changed() {
const new_progress = this.compute_progress();
this.task.progress = new_progress;
this.gantt.trigger_event("progress_change", [this.task, new_progress]);
this.gantt.trigger_event('progress_change', [this.task, new_progress]);
}
set_action_completed() {
@ -441,13 +464,13 @@ export default class Bar {
const new_start_date = date_utils.add(
this.gantt.gantt_start,
x_in_units * this.gantt.options.step,
"hour",
'hour',
);
const width_in_units = bar.getWidth() / this.gantt.options.column_width;
const new_end_date = date_utils.add(
new_start_date,
width_in_units * this.gantt.options.step,
"hour",
'hour',
);
return { new_start_date, new_end_date };
@ -461,7 +484,7 @@ export default class Bar {
compute_expected_progress() {
this.expected_progress =
date_utils.diff(date_utils.today(), this.task._start, "hour") /
date_utils.diff(date_utils.today(), this.task._start, 'hour') /
this.gantt.options.step;
this.expected_progress =
((this.expected_progress < this.duration
@ -476,11 +499,11 @@ export default class Bar {
const task_start = this.task._start;
const gantt_start = this.gantt.gantt_start;
const diff = date_utils.diff(task_start, gantt_start, "hour");
const diff = date_utils.diff(task_start, gantt_start, 'hour');
let x = (diff / step) * column_width;
if (this.gantt.view_is("Month")) {
const diff = date_utils.diff(task_start, gantt_start, "day");
if (this.gantt.view_is('Month')) {
const diff = date_utils.diff(task_start, gantt_start, 'day');
x = (diff * column_width) / 30;
}
this.x = x;
@ -495,7 +518,7 @@ export default class Bar {
compute_duration() {
this.duration =
date_utils.diff(this.task._end, this.task._start, "hour") /
date_utils.diff(this.task._end, this.task._start, 'hour') /
this.gantt.options.step;
}
@ -504,7 +527,7 @@ export default class Bar {
rem,
position;
if (this.gantt.view_is("Week")) {
if (this.gantt.view_is('Week')) {
rem = dx % (this.gantt.options.column_width / 7);
position =
odx -
@ -512,7 +535,7 @@ export default class Bar {
(rem < this.gantt.options.column_width / 14
? 0
: this.gantt.options.column_width / 7);
} else if (this.gantt.view_is("Month")) {
} else if (this.gantt.view_is('Month')) {
rem = dx % (this.gantt.options.column_width / 30);
position =
odx -
@ -542,10 +565,10 @@ export default class Bar {
update_expected_progressbar_position() {
if (this.invalid) return;
this.$expected_bar_progress.setAttribute("x", this.$bar.getX());
this.$expected_bar_progress.setAttribute('x', this.$bar.getX());
this.compute_expected_progress();
this.$expected_bar_progress.setAttribute(
"width",
'width',
this.gantt.options.column_width *
this.duration *
(this.expected_progress / 100) || 0,
@ -554,9 +577,9 @@ export default class Bar {
update_progressbar_position() {
if (this.invalid || this.gantt.options.readonly) return;
this.$bar_progress.setAttribute("x", this.$bar.getX());
this.$bar_progress.setAttribute('x', this.$bar.getX());
this.$bar_progress.setAttribute(
"width",
'width',
this.$bar.getWidth() * (this.task.progress / 100),
);
}
@ -564,31 +587,42 @@ export default class Bar {
update_label_position() {
const img_mask = this.bar_group.querySelector('.img_mask') || '';
const bar = this.$bar,
label = this.group.querySelector(".bar-label"),
label = this.group.querySelector('.bar-label'),
img = this.group.querySelector('.bar-img');
let padding = 5;
let x_offset_label_img = this.image_size + 10;
const labelWidth = label.getBBox().width
const barWidth = bar.getWidth()
const labelWidth = label.getBBox().width;
const barWidth = bar.getWidth();
if (labelWidth > barWidth) {
label.classList.add("big");
label.classList.add('big');
if (img) {
img.setAttribute('x', bar.getX() + bar.getWidth() + padding);
img_mask.setAttribute('x', bar.getX() + bar.getWidth() + padding);
label.setAttribute('x', bar.getX() + bar.getWidth() + x_offset_label_img);
img_mask.setAttribute(
'x',
bar.getX() + bar.getWidth() + padding,
);
label.setAttribute(
'x',
bar.getX() + bar.getWidth() + x_offset_label_img,
);
} else {
label.setAttribute('x', bar.getX() + bar.getWidth() + padding);
}
} else {
label.classList.remove("big");
label.classList.remove('big');
if (img) {
img.setAttribute('x', bar.getX() + padding);
img_mask.setAttribute('x', bar.getX() + padding);
label.setAttribute('x', bar.getX() + barWidth / 2 + x_offset_label_img);
label.setAttribute(
'x',
bar.getX() + barWidth / 2 + x_offset_label_img,
);
} else {
label.setAttribute('x', bar.getX() + barWidth / 2 - labelWidth / 2);
label.setAttribute(
'x',
bar.getX() + barWidth / 2 - labelWidth / 2,
);
}
}
}
@ -597,13 +631,14 @@ export default class Bar {
if (this.invalid || this.gantt.options.readonly) return;
const bar = this.$bar;
this.handle_group
.querySelector(".handle.left")
.setAttribute("x", bar.getX() - 12);
.querySelector('.handle.left')
.setAttribute('x', bar.getX() - 12);
this.handle_group
.querySelector(".handle.right")
.setAttribute("x", bar.getEndX() + 4);
const handle = this.group.querySelector(".handle.progress");
handle && handle.setAttribute("points", this.get_progress_polygon_points());
.querySelector('.handle.right')
.setAttribute('x', bar.getEndX() + 4);
const handle = this.group.querySelector('.handle.progress');
handle &&
handle.setAttribute('points', this.get_progress_polygon_points());
}
update_arrow_position() {
@ -618,6 +653,6 @@ function isFunction(functionToCheck) {
let getType = {};
return (
functionToCheck &&
getType.toString.call(functionToCheck) === "[object Function]"
getType.toString.call(functionToCheck) === '[object Function]'
);
}

View File

@ -1,24 +1,24 @@
const YEAR = "year";
const MONTH = "month";
const DAY = "day";
const HOUR = "hour";
const MINUTE = "minute";
const SECOND = "second";
const MILLISECOND = "millisecond";
const YEAR = 'year';
const MONTH = 'month';
const DAY = 'day';
const HOUR = 'hour';
const MINUTE = 'minute';
const SECOND = 'second';
const MILLISECOND = 'millisecond';
const SHORTENED = {
January: "Jan",
February: "Feb",
March: "Mar",
April: "Apr",
May: "May",
June: "Jun",
July: "Jul",
August: "Aug",
September: "Sep",
October: "Oct",
November: "Nov",
December: "Dec"
January: 'Jan',
February: 'Feb',
March: 'Mar',
April: 'Apr',
May: 'May',
June: 'Jun',
July: 'Jul',
August: 'Aug',
September: 'Sep',
October: 'Oct',
November: 'Nov',
December: 'Dec',
};
export default {
@ -27,30 +27,30 @@ export default {
const matches = regex.exec(duration);
if (matches !== null) {
if (matches[2] === "y") {
if (matches[2] === 'y') {
return { duration: parseInt(matches[1]), scale: `year` };
} else if (matches[2] === "m") {
} else if (matches[2] === 'm') {
return { duration: parseInt(matches[1]), scale: `month` };
} else if (matches[2] === "d") {
} else if (matches[2] === 'd') {
return { duration: parseInt(matches[1]), scale: `day` };
} else if (matches[2] === "h") {
} else if (matches[2] === 'h') {
return { duration: parseInt(matches[1]), scale: `hour` };
} else if (matches[2] === "min") {
} else if (matches[2] === 'min') {
return { duration: parseInt(matches[1]), scale: `minute` };
} else if (matches[2] === "s") {
} else if (matches[2] === 's') {
return { duration: parseInt(matches[1]), scale: `second` };
} else if (matches[2] === "ms") {
} else if (matches[2] === 'ms') {
return { duration: parseInt(matches[1]), scale: `millisecond` };
}
}
},
parse(date, date_separator = "-", time_separator = /[.:]/) {
parse(date, date_separator = '-', time_separator = /[.:]/) {
if (date instanceof Date) {
return date;
}
if (typeof date === "string") {
if (typeof date === 'string') {
let date_parts, time_parts;
const parts = date.split(" ");
const parts = date.split(' ');
date_parts = parts[0]
.split(date_separator)
.map((val) => parseInt(val, 10));
@ -63,7 +63,7 @@ export default {
if (time_parts && time_parts.length) {
if (time_parts.length === 4) {
time_parts[3] = "0." + time_parts[3];
time_parts[3] = '0.' + time_parts[3];
time_parts[3] = parseFloat(time_parts[3]) * 1000;
}
vals = vals.concat(time_parts);
@ -74,7 +74,7 @@ export default {
to_string(date, with_time = false) {
if (!(date instanceof Date)) {
throw new TypeError("Invalid argument type");
throw new TypeError('Invalid argument type');
}
const vals = this.get_date_values(date).map((val, i) => {
if (i === 1) {
@ -83,20 +83,20 @@ export default {
}
if (i === 6) {
return padStart(val + "", 3, "0");
return padStart(val + '', 3, '0');
}
return padStart(val + "", 2, "0");
return padStart(val + '', 2, '0');
});
const date_string = `${vals[0]}-${vals[1]}-${vals[2]}`;
const time_string = `${vals[3]}:${vals[4]}:${vals[5]}.${vals[6]}`;
return date_string + (with_time ? " " + time_string : "");
return date_string + (with_time ? ' ' + time_string : '');
},
format(date, format_string = "YYYY-MM-DD HH:mm:ss.SSS", lang = "en") {
format(date, format_string = 'YYYY-MM-DD HH:mm:ss.SSS', lang = 'en') {
const dateTimeFormat = new Intl.DateTimeFormat(lang, {
month: "long",
month: 'long',
});
const month_name = dateTimeFormat.format(date);
const month_name_capitalized =
@ -146,8 +146,8 @@ export default {
months = days / 30;
years = months / 12;
if (!scale.endsWith("s")) {
scale += "s";
if (!scale.endsWith('s')) {
scale += 's';
}
return Math.floor(
@ -251,9 +251,9 @@ export default {
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/padStart
function padStart(str, targetLength, padString) {
str = str + "";
str = str + '';
targetLength = targetLength >> 0;
padString = String(typeof padString !== "undefined" ? padString : " ");
padString = String(typeof padString !== 'undefined' ? padString : ' ');
if (str.length > targetLength) {
return String(str);
} else {

View File

@ -1,26 +1,25 @@
@import "./dark.scss";
@import './dark.scss';
$bar-color: #fff !default;
$bar-color-important: #94c4f4 !default;
$bar-stroke: #fff !default;
$dark-stroke-color: #e0e0e0 !default;
$stroke-color: #EBEEF0 !default;
$stroke-color: #ebeef0 !default;
$light-bg: #f5f5f5 !default;
$light-border-color: #ebeff2 !default;
$light-yellow: #f6e796 !default;
$holiday-color: #F9FAFA !default;
$holiday-color: #f9fafa !default;
$text-muted: #666 !default;
$text-grey: #98A1A9;
$text-grey: #98a1a9;
$text-light: #fff !default;
$text-dark: #111 !default;
$progress: #EBEEF0 !default;
$progress: #ebeef0 !default;
$handle-color: #dcdce4 !default;
$handle-color-important: #94c4f4 !default;
$light-blue: #c4c4e9 !default;
$middle-blue: #62B2F9 !default;
$middle-blue: #62b2f9 !default;
$dark-blue: #2c94ec !default;
.gantt-container {
line-height: 14.5px;
@ -74,7 +73,7 @@ $dark-blue: #2c94ec !default;
.today-button,
.viewmode-select {
background: #F4F5F6;
background: #f4f5f6;
text-align: -webkit-center;
text-align: center;
height: 25px;
@ -128,8 +127,6 @@ $dark-blue: #2c94ec !default;
fill: none;
}
.grid-row {
fill: #ffffff;
}
@ -152,15 +149,13 @@ $dark-blue: #2c94ec !default;
}
}
.holiday-highlight {
fill: $holiday-color;
}
.arrow {
fill: none;
stroke: #9FA9B1;
stroke: #9fa9b1;
stroke-width: 1;
}
@ -226,7 +221,6 @@ $dark-blue: #2c94ec !default;
}
}
.handle {
fill: $handle-color;
cursor: ew-resize;
@ -251,12 +245,11 @@ $dark-blue: #2c94ec !default;
}
.bar {
-webkit-filter: drop-shadow(3px 3px 2px rgba(0, 0, 0, .7));
filter: drop-shadow(0 0 2px rgba(17, 43, 66, .16));
-webkit-filter: drop-shadow(3px 3px 2px rgba(0, 0, 0, 0.7));
filter: drop-shadow(0 0 2px rgba(17, 43, 66, 0.16));
border-radius: 3px;
}
&:hover {
.bar {
transition: transform 0.3s ease;
@ -268,7 +261,6 @@ $dark-blue: #2c94ec !default;
}
}
.hide {
display: none;
}
@ -284,7 +276,7 @@ $dark-blue: #2c94ec !default;
position: absolute;
top: 0;
left: 0;
background: #171B1F;
background: #171b1f;
padding: 10px;
border-radius: 5px;
width: max-content;
@ -293,7 +285,6 @@ $dark-blue: #2c94ec !default;
opacity: 0 !important;
}
.title {
margin-bottom: 5px;
text-align: -webkit-center;

File diff suppressed because it is too large Load Diff

View File

@ -14,14 +14,14 @@ export default class Popup {
this.hide();
this.title = this.parent.querySelector(".title");
this.subtitle = this.parent.querySelector(".subtitle");
this.pointer = this.parent.querySelector(".pointer");
this.title = this.parent.querySelector('.title');
this.subtitle = this.parent.querySelector('.subtitle');
this.pointer = this.parent.querySelector('.pointer');
}
show(options) {
if (!options.target_element) {
throw new Error("target_element is required to show popup");
throw new Error('target_element is required to show popup');
}
const target_element = options.target_element;
@ -29,7 +29,7 @@ export default class Popup {
let html = this.custom_html(options.task);
html += '<div class="pointer"></div>';
this.parent.innerHTML = html;
this.pointer = this.parent.querySelector(".pointer");
this.pointer = this.parent.querySelector('.pointer');
} else {
// set data
this.title.innerHTML = options.title;
@ -44,11 +44,12 @@ export default class Popup {
position_meta = options.target_element.getBBox();
}
this.parent.style.left = options.x - this.parent.clientWidth / 2 + "px";
this.parent.style.top = position_meta.y + position_meta.height + 10 + "px";
this.parent.style.left = options.x - this.parent.clientWidth / 2 + 'px';
this.parent.style.top =
position_meta.y + position_meta.height + 10 + 'px';
this.pointer.style.left = this.parent.clientWidth / 2 + "px";
this.pointer.style.top = "-15px";
this.pointer.style.left = this.parent.clientWidth / 2 + 'px';
this.pointer.style.top = '-15px';
// show
this.parent.style.opacity = 1;

View File

@ -1,16 +1,16 @@
export function $(expr, con) {
return typeof expr === "string"
return typeof expr === 'string'
? (con || document).querySelector(expr)
: expr || null;
}
export function createSVG(tag, attrs) {
const elem = document.createElementNS("http://www.w3.org/2000/svg", tag);
const elem = document.createElementNS('http://www.w3.org/2000/svg', tag);
for (let attr in attrs) {
if (attr === "append_to") {
if (attr === 'append_to') {
const parent = attrs.append_to;
parent.appendChild(elem);
} else if (attr === "innerHTML") {
} else if (attr === 'innerHTML') {
elem.innerHTML = attrs.innerHTML;
} else if (attr === 'clipPath') {
elem.setAttribute('clip-path', 'url(#' + attrs[attr] + ')');
@ -27,9 +27,9 @@ export function animateSVG(svgElement, attr, from, to) {
if (animatedSvgElement === svgElement) {
// triggered 2nd time programmatically
// trigger artificial click event
const event = document.createEvent("HTMLEvents");
event.initEvent("click", true, true);
event.eventName = "click";
const event = document.createEvent('HTMLEvents');
event.initEvent('click', true, true);
event.eventName = 'click';
animatedSvgElement.dispatchEvent(event);
}
}
@ -39,31 +39,31 @@ function getAnimationElement(
attr,
from,
to,
dur = "0.4s",
begin = "0.1s",
dur = '0.4s',
begin = '0.1s',
) {
const animEl = svgElement.querySelector("animate");
const animEl = svgElement.querySelector('animate');
if (animEl) {
$.attr(animEl, {
attributeName: attr,
from,
to,
dur,
begin: "click + " + begin, // artificial click
begin: 'click + ' + begin, // artificial click
});
return svgElement;
}
const animateElement = createSVG("animate", {
const animateElement = createSVG('animate', {
attributeName: attr,
from,
to,
dur,
begin,
calcMode: "spline",
values: from + ";" + to,
keyTimes: "0; 1",
keySplines: cubic_bezier("ease-out"),
calcMode: 'spline',
values: from + ';' + to,
keyTimes: '0; 1',
keySplines: cubic_bezier('ease-out'),
});
svgElement.appendChild(animateElement);
@ -72,11 +72,11 @@ function getAnimationElement(
function cubic_bezier(name) {
return {
ease: ".25 .1 .25 1",
linear: "0 0 1 1",
"ease-in": ".42 0 1 1",
"ease-out": "0 0 .58 1",
"ease-in-out": ".42 0 .58 1",
ease: '.25 .1 .25 1',
linear: '0 0 1 1',
'ease-in': '.42 0 1 1',
'ease-out': '0 0 .58 1',
'ease-in-out': '.42 0 .58 1',
}[name];
}
@ -120,11 +120,11 @@ $.closest = (selector, element) => {
};
$.attr = (element, attr, value) => {
if (!value && typeof attr === "string") {
if (!value && typeof attr === 'string') {
return element.getAttribute(attr);
}
if (typeof attr === "object") {
if (typeof attr === 'object') {
for (let key in attr) {
$.attr(element, key, attr[key]);
}

View File

@ -1,15 +1,15 @@
import date_utils from "../src/date_utils";
import date_utils from '../src/date_utils';
test("Parse: parses string date", () => {
const date = date_utils.parse("2017-09-09");
test('Parse: parses string date', () => {
const date = date_utils.parse('2017-09-09');
expect(date.getDate()).toBe(9);
expect(date.getMonth()).toBe(8);
expect(date.getFullYear()).toBe(2017);
});
test("Parse: parses string datetime", () => {
const date = date_utils.parse("2017-08-27 16:08:34");
test('Parse: parses string datetime', () => {
const date = date_utils.parse('2017-08-27 16:08:34');
expect(date.getFullYear()).toBe(2017);
expect(date.getMonth()).toBe(7);
@ -19,8 +19,8 @@ test("Parse: parses string datetime", () => {
expect(date.getSeconds()).toBe(34);
});
test("Parse: parses string datetime", () => {
const date = date_utils.parse("2016-02-29 16:08:34.3");
test('Parse: parses string datetime', () => {
const date = date_utils.parse('2016-02-29 16:08:34.3');
expect(date.getFullYear()).toBe(2016);
expect(date.getMonth()).toBe(1);
@ -31,8 +31,8 @@ test("Parse: parses string datetime", () => {
expect(date.getMilliseconds()).toBe(300);
});
test("Parse: parses string datetime", () => {
const date = date_utils.parse("2015-07-01 00:00:59.200");
test('Parse: parses string datetime', () => {
const date = date_utils.parse('2015-07-01 00:00:59.200');
expect(date.getFullYear()).toBe(2015);
expect(date.getMonth()).toBe(6);
@ -43,82 +43,82 @@ test("Parse: parses string datetime", () => {
expect(date.getMilliseconds()).toBe(200);
});
test("Format: converts date object to string", () => {
const date = new Date("2017-09-18");
expect(date_utils.to_string(date)).toBe("2017-09-18");
test('Format: converts date object to string', () => {
const date = new Date('2017-09-18');
expect(date_utils.to_string(date)).toBe('2017-09-18');
});
test("Format: converts date object to string", () => {
const date = new Date("2016-02-29 16:08:34.3");
expect(date_utils.to_string(date, true)).toBe("2016-02-29 16:08:34.300");
test('Format: converts date object to string', () => {
const date = new Date('2016-02-29 16:08:34.3');
expect(date_utils.to_string(date, true)).toBe('2016-02-29 16:08:34.300');
});
test("Format: converts date object to string", () => {
const date = new Date("2016-02-29 16:08:34.3");
expect(date_utils.to_string(date, true)).toBe("2016-02-29 16:08:34.300");
test('Format: converts date object to string', () => {
const date = new Date('2016-02-29 16:08:34.3');
expect(date_utils.to_string(date, true)).toBe('2016-02-29 16:08:34.300');
});
test("Parse: returns Date Object as is", () => {
test('Parse: returns Date Object as is', () => {
const d = new Date();
const date = date_utils.parse(d);
expect(d).toBe(date);
});
test("Diff: returns diff between 2 date objects", () => {
const a = date_utils.parse("2017-09-08");
const b = date_utils.parse("2017-06-07");
test('Diff: returns diff between 2 date objects', () => {
const a = date_utils.parse('2017-09-08');
const b = date_utils.parse('2017-06-07');
expect(date_utils.diff(a, b, "day")).toBe(93);
expect(date_utils.diff(a, b, "month")).toBe(3);
expect(date_utils.diff(a, b, "year")).toBe(0);
expect(date_utils.diff(a, b, 'day')).toBe(93);
expect(date_utils.diff(a, b, 'month')).toBe(3);
expect(date_utils.diff(a, b, 'year')).toBe(0);
});
test("StartOf", () => {
const date = date_utils.parse("2017-08-12 15:07:34.012");
test('StartOf', () => {
const date = date_utils.parse('2017-08-12 15:07:34.012');
const start_of_millisecond = date_utils.start_of(date, "millisecond");
const start_of_millisecond = date_utils.start_of(date, 'millisecond');
expect(date_utils.to_string(start_of_millisecond, true)).toBe(
"2017-08-12 15:07:34.012",
'2017-08-12 15:07:34.012',
);
const start_of_second = date_utils.start_of(date, "second");
const start_of_second = date_utils.start_of(date, 'second');
expect(date_utils.to_string(start_of_second, true)).toBe(
"2017-08-12 15:07:34.000",
'2017-08-12 15:07:34.000',
);
const start_of_minute = date_utils.start_of(date, "minute");
const start_of_minute = date_utils.start_of(date, 'minute');
expect(date_utils.to_string(start_of_minute, true)).toBe(
"2017-08-12 15:07:00.000",
'2017-08-12 15:07:00.000',
);
const start_of_hour = date_utils.start_of(date, "hour");
const start_of_hour = date_utils.start_of(date, 'hour');
expect(date_utils.to_string(start_of_hour, true)).toBe(
"2017-08-12 15:00:00.000",
'2017-08-12 15:00:00.000',
);
const start_of_day = date_utils.start_of(date, "day");
const start_of_day = date_utils.start_of(date, 'day');
expect(date_utils.to_string(start_of_day, true)).toBe(
"2017-08-12 00:00:00.000",
'2017-08-12 00:00:00.000',
);
const start_of_month = date_utils.start_of(date, "month");
const start_of_month = date_utils.start_of(date, 'month');
expect(date_utils.to_string(start_of_month, true)).toBe(
"2017-08-01 00:00:00.000",
'2017-08-01 00:00:00.000',
);
const start_of_year = date_utils.start_of(date, "year");
const start_of_year = date_utils.start_of(date, 'year');
expect(date_utils.to_string(start_of_year, true)).toBe(
"2017-01-01 00:00:00.000",
'2017-01-01 00:00:00.000',
);
});
test("format", () => {
const date = date_utils.parse("2017-08-12 15:07:23");
expect(date_utils.format(date, "YYYY-MM-DD")).toBe("2017-08-12");
test('format', () => {
const date = date_utils.parse('2017-08-12 15:07:23');
expect(date_utils.format(date, 'YYYY-MM-DD')).toBe('2017-08-12');
});
test("format", () => {
const date = date_utils.parse("2016-02-29 16:08:34.3");
expect(date_utils.format(date)).toBe("2016-02-29 16:08:34.300");
test('format', () => {
const date = date_utils.parse('2016-02-29 16:08:34.3');
expect(date_utils.format(date)).toBe('2016-02-29 16:08:34.300');
});