adore-gantt 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/bar.js ADDED
@@ -0,0 +1,737 @@
1
+ import date_utils from './date_utils';
2
+ import { $, createSVG, animateSVG } from './svg_utils';
3
+
4
+ export default class Bar {
5
+ constructor(gantt, task) {
6
+ this.set_defaults(gantt, task);
7
+ this.prepare_wrappers();
8
+ this.prepare_helpers();
9
+ this.refresh();
10
+ }
11
+
12
+ refresh() {
13
+ this.bar_group.innerHTML = '';
14
+ this.handle_group.innerHTML = '';
15
+ if (this.task.custom_class) {
16
+ this.group.classList.add(this.task.custom_class);
17
+ } else {
18
+ this.group.classList = ['bar-wrapper'];
19
+ }
20
+
21
+ this.prepare_values();
22
+ this.draw();
23
+ this.bind();
24
+ }
25
+
26
+ set_defaults(gantt, task) {
27
+ this.action_completed = false;
28
+ this.gantt = gantt;
29
+ this.task = task;
30
+ this.name = this.name || '';
31
+ }
32
+
33
+ prepare_wrappers() {
34
+ this.group = createSVG('g', {
35
+ class:
36
+ 'bar-wrapper' +
37
+ (this.task.custom_class ? ' ' + this.task.custom_class : ''),
38
+ 'data-id': this.task.id,
39
+ });
40
+ this.bar_group = createSVG('g', {
41
+ class: 'bar-group',
42
+ append_to: this.group,
43
+ });
44
+ this.handle_group = createSVG('g', {
45
+ class: 'handle-group',
46
+ append_to: this.group,
47
+ });
48
+ }
49
+
50
+ prepare_values() {
51
+ this.invalid = this.task.invalid;
52
+ this.height = this.gantt.options.bar_height;
53
+ this.image_size = this.height - 5;
54
+ this.task._start = new Date(this.task.start);
55
+ this.task._end = new Date(this.task.end);
56
+ this.compute_x();
57
+ this.compute_y();
58
+ this.compute_duration();
59
+ this.corner_radius = this.gantt.options.bar_corner_radius;
60
+ this.width = this.gantt.config.column_width * this.duration;
61
+ if (!this.task.progress || this.task.progress < 0)
62
+ this.task.progress = 0;
63
+ if (this.task.progress > 100) this.task.progress = 100;
64
+ }
65
+
66
+ prepare_helpers() {
67
+ SVGElement.prototype.getX = function () {
68
+ return +this.getAttribute('x');
69
+ };
70
+ SVGElement.prototype.getY = function () {
71
+ return +this.getAttribute('y');
72
+ };
73
+ SVGElement.prototype.getWidth = function () {
74
+ return +this.getAttribute('width');
75
+ };
76
+ SVGElement.prototype.getHeight = function () {
77
+ return +this.getAttribute('height');
78
+ };
79
+ SVGElement.prototype.getEndX = function () {
80
+ return this.getX() + this.getWidth();
81
+ };
82
+ }
83
+
84
+ prepare_expected_progress_values() {
85
+ this.compute_expected_progress();
86
+ this.expected_progress_width =
87
+ this.gantt.options.column_width *
88
+ this.duration *
89
+ (this.expected_progress / 100) || 0;
90
+ }
91
+
92
+ draw() {
93
+ this.draw_bar();
94
+ this.draw_progress_bar();
95
+ if (this.gantt.options.show_expected_progress) {
96
+ this.prepare_expected_progress_values();
97
+ this.draw_expected_progress_bar();
98
+ }
99
+ this.draw_label();
100
+ this.draw_resize_handles();
101
+
102
+ if (this.task.thumbnail) {
103
+ this.draw_thumbnail();
104
+ }
105
+ }
106
+
107
+ draw_bar() {
108
+ this.$bar = createSVG('rect', {
109
+ x: this.x,
110
+ y: this.y,
111
+ width: this.width,
112
+ height: this.height,
113
+ rx: this.corner_radius,
114
+ ry: this.corner_radius,
115
+ class: 'bar',
116
+ append_to: this.bar_group,
117
+ });
118
+ if (this.task.color) this.$bar.style.fill = this.task.color;
119
+ animateSVG(this.$bar, 'width', 0, this.width);
120
+
121
+ if (this.invalid) {
122
+ this.$bar.classList.add('bar-invalid');
123
+ }
124
+ }
125
+
126
+ draw_expected_progress_bar() {
127
+ if (this.invalid) return;
128
+ this.$expected_bar_progress = createSVG('rect', {
129
+ x: this.x,
130
+ y: this.y,
131
+ width: this.expected_progress_width,
132
+ height: this.height,
133
+ rx: this.corner_radius,
134
+ ry: this.corner_radius,
135
+ class: 'bar-expected-progress',
136
+ append_to: this.bar_group,
137
+ });
138
+
139
+ animateSVG(
140
+ this.$expected_bar_progress,
141
+ 'width',
142
+ 0,
143
+ this.expected_progress_width,
144
+ );
145
+ }
146
+
147
+ draw_progress_bar() {
148
+ if (this.invalid) return;
149
+ this.progress_width = this.calculate_progress_width();
150
+ let r = this.corner_radius;
151
+ if (!/^((?!chrome|android).)*safari/i.test(navigator.userAgent))
152
+ r = this.corner_radius + 2;
153
+ this.$bar_progress = createSVG('rect', {
154
+ x: this.x,
155
+ y: this.y,
156
+ width: this.progress_width,
157
+ height: this.height,
158
+ rx: r,
159
+ ry: r,
160
+ class: 'bar-progress',
161
+ append_to: this.bar_group,
162
+ });
163
+ if (this.task.color_progress)
164
+ this.$bar_progress.style.fill = this.task.color_progress;
165
+ const x =
166
+ (date_utils.diff(
167
+ this.task._start,
168
+ this.gantt.gantt_start,
169
+ this.gantt.config.unit,
170
+ ) /
171
+ this.gantt.config.step) *
172
+ this.gantt.config.column_width;
173
+
174
+ let $date_highlight = this.gantt.create_el({
175
+ classes: `date-range-highlight hide highlight-${this.task.id}`,
176
+ width: this.width,
177
+ left: x,
178
+ });
179
+ this.$date_highlight = $date_highlight;
180
+ this.gantt.$lower_header.prepend(this.$date_highlight);
181
+
182
+ animateSVG(this.$bar_progress, 'width', 0, this.progress_width);
183
+ }
184
+
185
+ calculate_progress_width() {
186
+ const width = this.$bar.getWidth();
187
+ const ignored_end = this.x + width;
188
+ const total_ignored_area =
189
+ this.gantt.config.ignored_positions.reduce((acc, val) => {
190
+ return acc + (val >= this.x && val < ignored_end);
191
+ }, 0) * this.gantt.config.column_width;
192
+ let progress_width =
193
+ ((width - total_ignored_area) * this.task.progress) / 100;
194
+ const progress_end = this.x + progress_width;
195
+ const total_ignored_progress =
196
+ this.gantt.config.ignored_positions.reduce((acc, val) => {
197
+ return acc + (val >= this.x && val < progress_end);
198
+ }, 0) * this.gantt.config.column_width;
199
+
200
+ progress_width += total_ignored_progress;
201
+
202
+ let ignored_regions = this.gantt.get_ignored_region(
203
+ this.x + progress_width,
204
+ );
205
+
206
+ while (ignored_regions.length) {
207
+ progress_width += this.gantt.config.column_width;
208
+ ignored_regions = this.gantt.get_ignored_region(
209
+ this.x + progress_width,
210
+ );
211
+ }
212
+ this.progress_width = progress_width;
213
+ return progress_width;
214
+ }
215
+
216
+ draw_label() {
217
+ let x_coord = this.x + this.$bar.getWidth() / 2;
218
+
219
+ if (this.task.thumbnail) {
220
+ x_coord = this.x + this.image_size + 5;
221
+ }
222
+
223
+ createSVG('text', {
224
+ x: x_coord,
225
+ y: this.y + this.height / 2,
226
+ innerHTML: this.task.name,
227
+ class: 'bar-label',
228
+ append_to: this.bar_group,
229
+ });
230
+ // labels get BBox in the next tick
231
+ requestAnimationFrame(() => this.update_label_position());
232
+ }
233
+
234
+ draw_thumbnail() {
235
+ let x_offset = 10,
236
+ y_offset = 2;
237
+ let defs, clipPath;
238
+
239
+ defs = createSVG('defs', {
240
+ append_to: this.bar_group,
241
+ });
242
+
243
+ createSVG('rect', {
244
+ id: 'rect_' + this.task.id,
245
+ x: this.x + x_offset,
246
+ y: this.y + y_offset,
247
+ width: this.image_size,
248
+ height: this.image_size,
249
+ rx: '15',
250
+ class: 'img_mask',
251
+ append_to: defs,
252
+ });
253
+
254
+ clipPath = createSVG('clipPath', {
255
+ id: 'clip_' + this.task.id,
256
+ append_to: defs,
257
+ });
258
+
259
+ createSVG('use', {
260
+ href: '#rect_' + this.task.id,
261
+ append_to: clipPath,
262
+ });
263
+
264
+ createSVG('image', {
265
+ x: this.x + x_offset,
266
+ y: this.y + y_offset,
267
+ width: this.image_size,
268
+ height: this.image_size,
269
+ class: 'bar-img',
270
+ href: this.task.thumbnail,
271
+ clipPath: 'clip_' + this.task.id,
272
+ append_to: this.bar_group,
273
+ });
274
+ }
275
+
276
+ draw_resize_handles() {
277
+ if (this.invalid || this.gantt.options.readonly) return;
278
+
279
+ const bar = this.$bar;
280
+ const handle_width = 3;
281
+ this.handles = [];
282
+ if (!this.gantt.options.readonly_dates) {
283
+ this.handles.push(
284
+ createSVG('rect', {
285
+ x: bar.getEndX() - handle_width / 2,
286
+ y: bar.getY() + this.height / 4,
287
+ width: handle_width,
288
+ height: this.height / 2,
289
+ rx: 2,
290
+ ry: 2,
291
+ class: 'handle right',
292
+ append_to: this.handle_group,
293
+ }),
294
+ );
295
+
296
+ this.handles.push(
297
+ createSVG('rect', {
298
+ x: bar.getX() - handle_width / 2,
299
+ y: bar.getY() + this.height / 4,
300
+ width: handle_width,
301
+ height: this.height / 2,
302
+ rx: 2,
303
+ ry: 2,
304
+ class: 'handle left',
305
+ append_to: this.handle_group,
306
+ }),
307
+ );
308
+ }
309
+ if (!this.gantt.options.readonly_progress) {
310
+ const bar_progress = this.$bar_progress;
311
+ this.$handle_progress = createSVG('circle', {
312
+ cx: bar_progress.getEndX(),
313
+ cy: bar_progress.getY() + bar_progress.getHeight() / 2,
314
+ r: 4.5,
315
+ class: 'handle progress',
316
+ append_to: this.handle_group,
317
+ });
318
+ this.handles.push(this.$handle_progress);
319
+ }
320
+
321
+ for (let handle of this.handles) {
322
+ $.on(handle, 'mouseenter', () => handle.classList.add('active'));
323
+ $.on(handle, 'mouseleave', () => handle.classList.remove('active'));
324
+ }
325
+ }
326
+
327
+ bind() {
328
+ if (this.invalid) return;
329
+ this.setup_click_event();
330
+ }
331
+
332
+ setup_click_event() {
333
+ let task_id = this.task.id;
334
+ $.on(this.group, 'mouseover', (e) => {
335
+ this.gantt.trigger_event('hover', [
336
+ this.task,
337
+ e.screenX,
338
+ e.screenY,
339
+ e,
340
+ ]);
341
+ });
342
+
343
+ if (this.gantt.options.popup_on === 'click') {
344
+ $.on(this.group, 'mouseup', (e) => {
345
+ const posX = e.offsetX || e.layerX;
346
+ if (this.$handle_progress) {
347
+ const cx = +this.$handle_progress.getAttribute('cx');
348
+ if (cx > posX - 1 && cx < posX + 1) return;
349
+ if (this.gantt.bar_being_dragged) return;
350
+ }
351
+ this.gantt.show_popup({
352
+ x: e.offsetX || e.layerX,
353
+ y: e.offsetY || e.layerY,
354
+ task: this.task,
355
+ target: this.$bar,
356
+ });
357
+ });
358
+ }
359
+ let timeout;
360
+ $.on(this.group, 'mouseenter', (e) => {
361
+ timeout = setTimeout(() => {
362
+ if (this.gantt.options.popup_on === 'hover')
363
+ this.gantt.show_popup({
364
+ x: e.offsetX || e.layerX,
365
+ y: e.offsetY || e.layerY,
366
+ task: this.task,
367
+ target: this.$bar,
368
+ });
369
+ this.gantt.$container
370
+ .querySelector(`.highlight-${task_id}`)
371
+ .classList.remove('hide');
372
+ }, 200);
373
+ });
374
+ $.on(this.group, 'mouseleave', () => {
375
+ clearTimeout(timeout);
376
+ if (this.gantt.options.popup_on === 'hover')
377
+ this.gantt.popup?.hide?.();
378
+ this.gantt.$container
379
+ .querySelector(`.highlight-${task_id}`)
380
+ .classList.add('hide');
381
+ });
382
+
383
+ $.on(this.group, 'click', () => {
384
+ this.gantt.trigger_event('click', [this.task]);
385
+ });
386
+
387
+ $.on(this.group, 'dblclick', (e) => {
388
+ if (this.action_completed) {
389
+ // just finished a move action, wait for a few seconds
390
+ return;
391
+ }
392
+ this.group.classList.remove('active');
393
+ if (this.gantt.popup)
394
+ this.gantt.popup.parent.classList.remove('hide');
395
+
396
+ this.gantt.trigger_event('double_click', [this.task]);
397
+ });
398
+ let tapedTwice = false;
399
+ $.on(this.group, 'touchstart', (e) => {
400
+ if (!tapedTwice) {
401
+ tapedTwice = true;
402
+ setTimeout(function () {
403
+ tapedTwice = false;
404
+ }, 300);
405
+ return false;
406
+ }
407
+ e.preventDefault();
408
+ //action on double tap goes below
409
+
410
+ if (this.action_completed) {
411
+ // just finished a move action, wait for a few seconds
412
+ return;
413
+ }
414
+ this.group.classList.remove('active');
415
+ if (this.gantt.popup)
416
+ this.gantt.popup.parent.classList.remove('hide');
417
+
418
+ this.gantt.trigger_event('double_click', [this.task]);
419
+ });
420
+ }
421
+
422
+ update_bar_position({ x = null, width = null }) {
423
+ const bar = this.$bar;
424
+
425
+ if (x) {
426
+ const xs = this.task.dependencies.map((dep) => {
427
+ return this.gantt.get_bar(dep).$bar.getX();
428
+ });
429
+ const valid_x = xs.reduce((prev, curr) => {
430
+ return prev && x >= curr;
431
+ }, true);
432
+ if (!valid_x) return;
433
+ this.update_attr(bar, 'x', x);
434
+ this.x = x;
435
+ this.$date_highlight.style.left = x + 'px';
436
+ }
437
+ if (width > 0) {
438
+ this.update_attr(bar, 'width', width);
439
+ this.$date_highlight.style.width = width + 'px';
440
+ }
441
+
442
+ this.update_label_position();
443
+ this.update_handle_position();
444
+ this.date_changed();
445
+ this.compute_duration();
446
+
447
+ if (this.gantt.options.show_expected_progress) {
448
+ this.update_expected_progressbar_position();
449
+ }
450
+
451
+ this.update_progressbar_position();
452
+ this.update_arrow_position();
453
+ }
454
+
455
+ update_label_position_on_horizontal_scroll({ x, sx }) {
456
+ const container = this.gantt.$container;
457
+ const label = this.group.querySelector('.bar-label');
458
+ const img = this.group.querySelector('.bar-img') || '';
459
+ const img_mask = this.bar_group.querySelector('.img_mask') || '';
460
+
461
+ let barWidthLimit = this.$bar.getX() + this.$bar.getWidth();
462
+ let newLabelX = label.getX() + x;
463
+ let newImgX = (img && img.getX() + x) || 0;
464
+ let imgWidth = (img && img.getBBox().width + 7) || 7;
465
+ let labelEndX = newLabelX + label.getBBox().width + 7;
466
+ let viewportCentral = sx + container.clientWidth / 2;
467
+
468
+ if (label.classList.contains('big')) return;
469
+
470
+ if (labelEndX < barWidthLimit && x > 0 && labelEndX < viewportCentral) {
471
+ label.setAttribute('x', newLabelX);
472
+ if (img) {
473
+ img.setAttribute('x', newImgX);
474
+ img_mask.setAttribute('x', newImgX);
475
+ }
476
+ } else if (
477
+ newLabelX - imgWidth > this.$bar.getX() &&
478
+ x < 0 &&
479
+ labelEndX > viewportCentral
480
+ ) {
481
+ label.setAttribute('x', newLabelX);
482
+ if (img) {
483
+ img.setAttribute('x', newImgX);
484
+ img_mask.setAttribute('x', newImgX);
485
+ }
486
+ }
487
+ }
488
+
489
+ date_changed() {
490
+ let changed = false;
491
+ const { new_start_date, new_end_date } = this.compute_start_end_date();
492
+ if (Number(this.task._start) !== Number(new_start_date)) {
493
+ changed = true;
494
+ this.task._start = new_start_date;
495
+ }
496
+
497
+ if (Number(this.task._end) !== Number(new_end_date)) {
498
+ changed = true;
499
+ this.task._end = new_end_date;
500
+ }
501
+
502
+ if (!changed) return;
503
+
504
+ this.gantt.trigger_event('date_change', [
505
+ this.task,
506
+ new_start_date,
507
+ date_utils.add(new_end_date, -1, 'second'),
508
+ ]);
509
+ }
510
+
511
+ progress_changed() {
512
+ this.task.progress = this.compute_progress();
513
+ this.gantt.trigger_event('progress_change', [
514
+ this.task,
515
+ this.task.progress,
516
+ ]);
517
+ }
518
+
519
+ set_action_completed() {
520
+ this.action_completed = true;
521
+ setTimeout(() => (this.action_completed = false), 1000);
522
+ }
523
+
524
+ compute_start_end_date() {
525
+ const bar = this.$bar;
526
+ const x_in_units = bar.getX() / this.gantt.config.column_width;
527
+ let new_start_date = date_utils.add(
528
+ this.gantt.gantt_start,
529
+ x_in_units * this.gantt.config.step,
530
+ this.gantt.config.unit,
531
+ );
532
+
533
+ const width_in_units = bar.getWidth() / this.gantt.config.column_width;
534
+ const new_end_date = date_utils.add(
535
+ new_start_date,
536
+ width_in_units * this.gantt.config.step,
537
+ this.gantt.config.unit,
538
+ );
539
+
540
+ return { new_start_date, new_end_date };
541
+ }
542
+
543
+ compute_progress() {
544
+ this.progress_width = this.$bar_progress.getWidth();
545
+ this.x = this.$bar_progress.getBBox().x;
546
+ const progress_area = this.x + this.progress_width;
547
+ const progress =
548
+ this.progress_width -
549
+ this.gantt.config.ignored_positions.reduce((acc, val) => {
550
+ return acc + (val >= this.x && val <= progress_area);
551
+ }, 0) *
552
+ this.gantt.config.column_width;
553
+ if (progress < 0) return 0;
554
+ const total =
555
+ this.$bar.getWidth() -
556
+ this.ignored_duration_raw * this.gantt.config.column_width;
557
+ return parseInt((progress / total) * 100, 10);
558
+ }
559
+
560
+ compute_expected_progress() {
561
+ this.expected_progress =
562
+ date_utils.diff(date_utils.today(), this.task._start, 'hour') /
563
+ this.gantt.config.step;
564
+ this.expected_progress =
565
+ ((this.expected_progress < this.duration
566
+ ? this.expected_progress
567
+ : this.duration) *
568
+ 100) /
569
+ this.duration;
570
+ }
571
+
572
+ compute_x() {
573
+ const { column_width } = this.gantt.config;
574
+ const task_start = this.task._start;
575
+ const gantt_start = this.gantt.gantt_start;
576
+
577
+ const diff =
578
+ date_utils.diff(task_start, gantt_start, this.gantt.config.unit) /
579
+ this.gantt.config.step;
580
+
581
+ let x = diff * column_width;
582
+
583
+ /* Since the column width is based on 30,
584
+ we count the month-difference, multiply it by 30 for a "pseudo-month"
585
+ and then add the days in the month, making sure the number does not exceed 29
586
+ so it is within the column */
587
+
588
+ // if (this.gantt.view_is('Month')) {
589
+ // const diffDaysBasedOn30DayMonths =
590
+ // date_utils.diff(task_start, gantt_start, 'month') * 30;
591
+ // const dayInMonth = Math.min(
592
+ // 29,
593
+ // date_utils.format(
594
+ // task_start,
595
+ // 'DD',
596
+ // this.gantt.options.language,
597
+ // ),
598
+ // );
599
+ // const diff = diffDaysBasedOn30DayMonths + dayInMonth;
600
+
601
+ // x = (diff * column_width) / 30;
602
+ // }
603
+
604
+ this.x = x;
605
+ }
606
+
607
+ compute_y() {
608
+ this.y =
609
+ this.gantt.config.header_height +
610
+ this.gantt.options.padding / 2 +
611
+ this.task._index * (this.height + this.gantt.options.padding);
612
+ }
613
+
614
+ compute_duration() {
615
+ let actual_duration_in_days = 0,
616
+ duration_in_days = 0;
617
+ for (
618
+ let d = new Date(this.task._start);
619
+ d < this.task._end;
620
+ d.setDate(d.getDate() + 1)
621
+ ) {
622
+ duration_in_days++;
623
+ if (
624
+ !this.gantt.config.ignored_dates.find(
625
+ (k) => k.getTime() === d.getTime(),
626
+ ) &&
627
+ (!this.gantt.config.ignored_function ||
628
+ !this.gantt.config.ignored_function(d))
629
+ ) {
630
+ actual_duration_in_days++;
631
+ }
632
+ }
633
+ this.task.actual_duration = actual_duration_in_days;
634
+ this.task.ignored_duration = duration_in_days - actual_duration_in_days;
635
+
636
+ this.duration =
637
+ date_utils.convert_scales(
638
+ duration_in_days + 'd',
639
+ this.gantt.config.unit,
640
+ ) / this.gantt.config.step;
641
+
642
+ this.actual_duration_raw =
643
+ date_utils.convert_scales(
644
+ actual_duration_in_days + 'd',
645
+ this.gantt.config.unit,
646
+ ) / this.gantt.config.step;
647
+
648
+ this.ignored_duration_raw = this.duration - this.actual_duration_raw;
649
+ }
650
+
651
+ update_attr(element, attr, value) {
652
+ value = +value;
653
+ if (!isNaN(value)) {
654
+ element.setAttribute(attr, value);
655
+ }
656
+ return element;
657
+ }
658
+
659
+ update_expected_progressbar_position() {
660
+ if (this.invalid) return;
661
+ this.$expected_bar_progress.setAttribute('x', this.$bar.getX());
662
+ this.compute_expected_progress();
663
+ this.$expected_bar_progress.setAttribute(
664
+ 'width',
665
+ this.gantt.config.column_width *
666
+ this.actual_duration_raw *
667
+ (this.expected_progress / 100) || 0,
668
+ );
669
+ }
670
+
671
+ update_progressbar_position() {
672
+ if (this.invalid || this.gantt.options.readonly) return;
673
+ this.$bar_progress.setAttribute('x', this.$bar.getX());
674
+
675
+ this.$bar_progress.setAttribute(
676
+ 'width',
677
+ this.calculate_progress_width(),
678
+ );
679
+ }
680
+
681
+ update_label_position() {
682
+ const img_mask = this.bar_group.querySelector('.img_mask') || '';
683
+ const bar = this.$bar,
684
+ label = this.group.querySelector('.bar-label'),
685
+ img = this.group.querySelector('.bar-img');
686
+
687
+ let padding = 5;
688
+ let x_offset_label_img = this.image_size + 10;
689
+ const labelWidth = label.getBBox().width;
690
+ const barWidth = bar.getWidth();
691
+ if (labelWidth > barWidth) {
692
+ label.classList.add('big');
693
+ if (img) {
694
+ img.setAttribute('x', bar.getEndX() + padding);
695
+ img_mask.setAttribute('x', bar.getEndX() + padding);
696
+ label.setAttribute('x', bar.getEndX() + x_offset_label_img);
697
+ } else {
698
+ label.setAttribute('x', bar.getEndX() + padding);
699
+ }
700
+ } else {
701
+ label.classList.remove('big');
702
+ if (img) {
703
+ img.setAttribute('x', bar.getX() + padding);
704
+ img_mask.setAttribute('x', bar.getX() + padding);
705
+ label.setAttribute(
706
+ 'x',
707
+ bar.getX() + barWidth / 2 + x_offset_label_img,
708
+ );
709
+ } else {
710
+ label.setAttribute(
711
+ 'x',
712
+ bar.getX() + barWidth / 2 - labelWidth / 2,
713
+ );
714
+ }
715
+ }
716
+ }
717
+
718
+ update_handle_position() {
719
+ if (this.invalid || this.gantt.options.readonly) return;
720
+ const bar = this.$bar;
721
+ this.handle_group
722
+ .querySelector('.handle.left')
723
+ .setAttribute('x', bar.getX());
724
+ this.handle_group
725
+ .querySelector('.handle.right')
726
+ .setAttribute('x', bar.getEndX());
727
+ const handle = this.group.querySelector('.handle.progress');
728
+ handle && handle.setAttribute('cx', this.$bar_progress.getEndX());
729
+ }
730
+
731
+ update_arrow_position() {
732
+ this.arrows = this.arrows || [];
733
+ for (let arrow of this.arrows) {
734
+ arrow.update();
735
+ }
736
+ }
737
+ }