|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418 |
- import date_utils from './date_utils';
- import { $, createSVG, animateSVG } from './svg_utils';
-
- export default class Bar {
- constructor(gantt, task) {
- this.set_defaults(gantt, task);
- this.prepare();
- this.draw();
- this.bind();
- }
-
- set_defaults(gantt, task) {
- this.action_completed = false;
- this.gantt = gantt;
- this.task = task;
- }
-
- prepare() {
- this.prepare_values();
- this.prepare_helpers();
- }
-
- prepare_values() {
- this.invalid = this.task.invalid;
- this.height = this.gantt.options.bar_height;
- this.x = this.compute_x();
- this.y = this.compute_y();
- this.corner_radius = this.gantt.options.bar_corner_radius;
- this.duration =
- date_utils.diff(this.task._end, this.task._start, 'hour') /
- this.gantt.options.step;
- this.width = this.gantt.options.column_width * this.duration;
- this.progress_width =
- this.gantt.options.column_width *
- this.duration *
- (this.task.progress / 100) || 0;
- this.group = createSVG('g', {
- class: 'bar-wrapper ' + (this.task.custom_class || ''),
- 'data-id': this.task.id,
- });
- this.bar_group = createSVG('g', {
- class: 'bar-group',
- append_to: this.group,
- });
- this.handle_group = createSVG('g', {
- class: 'handle-group',
- append_to: this.group,
- });
- }
-
- prepare_helpers() {
- SVGElement.prototype.getX = function () {
- return +this.getAttribute('x');
- };
- SVGElement.prototype.getY = function () {
- return +this.getAttribute('y');
- };
- SVGElement.prototype.getWidth = function () {
- return +this.getAttribute('width');
- };
- SVGElement.prototype.getHeight = function () {
- return +this.getAttribute('height');
- };
- SVGElement.prototype.getEndX = function () {
- return this.getX() + this.getWidth();
- };
- }
-
- draw() {
- this.draw_bar();
- this.draw_progress_bar();
- this.draw_label();
- this.draw_resize_handles();
- }
-
- draw_bar() {
- 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',
- append_to: this.bar_group,
- });
-
- animateSVG(this.$bar, 'width', 0, this.width);
-
- if (this.invalid) {
- this.$bar.classList.add('bar-invalid');
- }
- }
-
- draw_progress_bar() {
- if (this.invalid) return;
- 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',
- append_to: this.bar_group,
- });
-
- animateSVG(this.$bar_progress, 'width', 0, this.progress_width);
- }
-
- draw_label() {
- createSVG('text', {
- x: this.x + this.width / 2,
- y: this.y + this.height / 2,
- innerHTML: this.task.name,
- class: 'bar-label',
- append_to: this.bar_group,
- });
- // labels get BBox in the next tick
- requestAnimationFrame(() => this.update_label_position());
- }
-
- draw_resize_handles() {
- if (this.invalid) return;
-
- const bar = this.$bar;
- const handle_width = 8;
-
- createSVG('rect', {
- x: bar.getX() + bar.getWidth() - 9,
- y: bar.getY() + 1,
- width: handle_width,
- height: this.height - 2,
- rx: this.corner_radius,
- ry: this.corner_radius,
- class: 'handle right',
- append_to: this.handle_group,
- });
-
- createSVG('rect', {
- x: bar.getX() + 1,
- y: bar.getY() + 1,
- width: handle_width,
- height: this.height - 2,
- rx: this.corner_radius,
- ry: this.corner_radius,
- class: 'handle left',
- append_to: this.handle_group,
- });
-
- if (this.task.progress && this.task.progress < 100) {
- this.$handle_progress = createSVG('polygon', {
- points: this.get_progress_polygon_points().join(','),
- class: 'handle progress',
- append_to: this.handle_group,
- });
- }
- }
-
- get_progress_polygon_points() {
- const bar_progress = this.$bar_progress;
- return [
- bar_progress.getEndX() - 5,
- bar_progress.getY() + bar_progress.getHeight(),
- bar_progress.getEndX() + 5,
- bar_progress.getY() + bar_progress.getHeight(),
- bar_progress.getEndX(),
- bar_progress.getY() + bar_progress.getHeight() - 8.66,
- ];
- }
-
- bind() {
- if (this.invalid) return;
- this.setup_click_event();
- }
-
- setup_click_event() {
- $.on(this.group, 'focus ' + this.gantt.options.popup_trigger, (e) => {
- if (this.action_completed) {
- // just finished a move action, wait for a few seconds
- return;
- }
-
- this.show_popup();
- this.gantt.unselect_all();
- this.group.classList.add('active');
- });
-
- $.on(this.group, 'dblclick', (e) => {
- if (this.action_completed) {
- // just finished a move action, wait for a few seconds
- return;
- }
-
- this.gantt.trigger_event('click', [this.task]);
- });
- }
-
- show_popup() {
- if (this.gantt.bar_being_dragged) return;
-
- const start_date = date_utils.format(
- this.task._start,
- 'MMM D',
- this.gantt.options.language
- );
- const end_date = date_utils.format(
- date_utils.add(this.task._end, -1, 'second'),
- 'MMM D',
- this.gantt.options.language
- );
- const subtitle = start_date + ' - ' + end_date;
-
- this.gantt.show_popup({
- target_element: this.$bar,
- title: this.task.name,
- subtitle: subtitle,
- task: this.task,
- });
- }
-
- update_bar_position({ x = null, width = null }) {
- const bar = this.$bar;
- if (x) {
- // get all x values of parent task
- const xs = this.task.dependencies.map((dep) => {
- return this.gantt.get_bar(dep).$bar.getX();
- });
- // child task must not go before parent
- const valid_x = xs.reduce((prev, curr) => {
- return x >= curr;
- }, x);
- if (!valid_x) {
- width = null;
- return;
- }
- this.update_attr(bar, 'x', x);
- }
- if (width && width >= this.gantt.options.column_width) {
- this.update_attr(bar, 'width', width);
- }
- this.update_label_position();
- this.update_handle_position();
- this.update_progressbar_position();
- this.update_arrow_position();
- }
-
- date_changed() {
- let changed = false;
- const { new_start_date, new_end_date } = this.compute_start_end_date();
-
- if (Number(this.task._start) !== Number(new_start_date)) {
- changed = true;
- this.task._start = new_start_date;
- }
-
- if (Number(this.task._end) !== Number(new_end_date)) {
- changed = true;
- this.task._end = new_end_date;
- }
-
- if (!changed) return;
-
- this.gantt.trigger_event('date_change', [
- this.task,
- new_start_date,
- 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]);
- }
-
- set_action_completed() {
- this.action_completed = true;
- setTimeout(() => (this.action_completed = false), 1000);
- }
-
- compute_start_end_date() {
- const bar = this.$bar;
- const x_in_units = bar.getX() / this.gantt.options.column_width;
- const new_start_date = date_utils.add(
- this.gantt.gantt_start,
- x_in_units * this.gantt.options.step,
- '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'
- );
-
- return { new_start_date, new_end_date };
- }
-
- compute_progress() {
- const progress =
- (this.$bar_progress.getWidth() / this.$bar.getWidth()) * 100;
- return parseInt(progress, 10);
- }
-
- compute_x() {
- const { step, column_width } = this.gantt.options;
- const task_start = this.task._start;
- const gantt_start = this.gantt.gantt_start;
-
- 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');
- x = (diff * column_width) / 30;
- }
- return x;
- }
-
- compute_y() {
- return (
- this.gantt.options.header_height +
- this.gantt.options.padding +
- this.task._index * (this.height + this.gantt.options.padding)
- );
- }
-
- get_snap_position(dx) {
- let odx = dx,
- rem,
- position;
-
- if (this.gantt.view_is('Week')) {
- rem = dx % (this.gantt.options.column_width / 7);
- position =
- odx -
- rem +
- (rem < this.gantt.options.column_width / 14
- ? 0
- : this.gantt.options.column_width / 7);
- } else if (this.gantt.view_is('Month')) {
- rem = dx % (this.gantt.options.column_width / 30);
- position =
- odx -
- rem +
- (rem < this.gantt.options.column_width / 60
- ? 0
- : this.gantt.options.column_width / 30);
- } else {
- rem = dx % this.gantt.options.column_width;
- position =
- odx -
- rem +
- (rem < this.gantt.options.column_width / 2
- ? 0
- : this.gantt.options.column_width);
- }
- return position;
- }
-
- update_attr(element, attr, value) {
- value = +value;
- if (!isNaN(value)) {
- element.setAttribute(attr, value);
- }
- return element;
- }
-
- update_progressbar_position() {
- this.$bar_progress.setAttribute('x', this.$bar.getX());
- this.$bar_progress.setAttribute(
- 'width',
- this.$bar.getWidth() * (this.task.progress / 100)
- );
- }
-
- update_label_position() {
- const bar = this.$bar,
- label = this.group.querySelector('.bar-label');
-
- if (label.getBBox().width > bar.getWidth()) {
- label.classList.add('big');
- label.setAttribute('x', bar.getX() + bar.getWidth() + 5);
- } else {
- label.classList.remove('big');
- label.setAttribute('x', bar.getX() + bar.getWidth() / 2);
- }
- }
-
- update_handle_position() {
- const bar = this.$bar;
- this.handle_group
- .querySelector('.handle.left')
- .setAttribute('x', bar.getX() + 1);
- this.handle_group
- .querySelector('.handle.right')
- .setAttribute('x', bar.getEndX() - 9);
- const handle = this.group.querySelector('.handle.progress');
- handle &&
- handle.setAttribute('points', this.get_progress_polygon_points());
- }
-
- update_arrow_position() {
- this.arrows = this.arrows || [];
- for (let arrow of this.arrows) {
- arrow.update();
- }
- }
- }
-
- function isFunction(functionToCheck) {
- var getType = {};
- return (
- functionToCheck &&
- getType.toString.call(functionToCheck) === '[object Function]'
- );
- }
|