UNPKG

ng-devui

Version:

DevUI components based on Angular

860 lines (856 loc) 129 kB
import * as i0 from '@angular/core'; import { Injectable, Component, ViewChild, Input, EventEmitter, Output, Directive, Inject, HostListener, NgModule } from '@angular/core'; import { Subject, ReplaySubject, Observable, fromEvent, merge } from 'rxjs'; import { pluck, tap, map, distinctUntilChanged, takeUntil } from 'rxjs/operators'; import * as i2 from '@angular/common'; import { DOCUMENT, CommonModule } from '@angular/common'; import * as i3 from 'ng-devui/tooltip'; import { TooltipModule } from 'ng-devui/tooltip'; import * as i3$1 from '@angular/cdk/overlay'; import { OverlayModule } from '@angular/cdk/overlay'; import * as i2$1 from 'ng-devui/i18n'; import * as i3$2 from 'ng-devui/button'; import { ButtonModule } from 'ng-devui/button'; import * as i4 from 'ng-devui/dropdown'; import { DropDownModule } from 'ng-devui/dropdown'; import { PopoverModule } from 'ng-devui/popover'; var GanttScaleUnit; (function (GanttScaleUnit) { GanttScaleUnit["day"] = "day"; GanttScaleUnit["week"] = "week"; GanttScaleUnit["month"] = "month"; })(GanttScaleUnit || (GanttScaleUnit = {})); var GanttMarkerType; (function (GanttMarkerType) { GanttMarkerType["milestone"] = "milestone"; GanttMarkerType["month"] = "month"; GanttMarkerType["week"] = "week"; })(GanttMarkerType || (GanttMarkerType = {})); var UnitRole; (function (UnitRole) { UnitRole[UnitRole["day"] = 10] = "day"; UnitRole[UnitRole["week"] = 20] = "week"; UnitRole[UnitRole["month"] = 30] = "month"; })(UnitRole || (UnitRole = {})); class GanttService { static { this.DAY_DURATION = 24 * 60 * 60 * 1000; } constructor() { this.scaleUnit = GanttScaleUnit.day; this.ganttBarStatusChange = new Subject(); this.ganttScaleConfigChange = new ReplaySubject(1); this.mouseMoveListener = new Observable(); this.mouseEndListener = new Observable(); } changeGanttBarStatus(status) { this.ganttBarStatusChange.next(status); } registContainerEvents(scrollContainer) { // 背景拖拽 this.mouseDownListener = fromEvent(scrollContainer, 'mousedown').pipe(pluck('pageX')); this.mouseMoveListener = fromEvent(scrollContainer, 'mousemove').pipe(pluck('pageX')); this.mouseEndListener = merge(fromEvent(scrollContainer, 'mouseup'), fromEvent(scrollContainer, 'mouseout')).pipe(pluck('pageX')); } changeGanttScaleConfig(status) { this.ganttScaleConfigChange.next(status); } setScaleConfig(config) { if (config.startDate) { this.scaleStartDate = config.startDate; } if (config.endDate) { this.scaleEndDate = config.endDate; } if (config.unit) { this.scaleUnit = config.unit; } this.changeGanttScaleConfig(config); } getScaleUnitPixel() { switch (this.scaleUnit) { case GanttScaleUnit.day: return 40; break; case GanttScaleUnit.week: return 30; break; case GanttScaleUnit.month: return 20; break; default: break; } } getDatePostionOffset(date) { if (date && this.scaleStartDate) { const timeOffset = date.getTime() - this.scaleStartDate.getTime(); const units = timeOffset / GanttService.DAY_DURATION; return units * this.getScaleUnitPixel(); } } getDuration(startDate, endDate) { if (startDate && endDate) { const timeOffset = endDate.getTime() - startDate.getTime(); const duration = timeOffset / GanttService.DAY_DURATION + 1; return Math.round(duration); } } getDurationWidth(startDate, endDate) { if (startDate && endDate) { const duration = this.getDuration(startDate, endDate); return duration * this.getScaleUnitPixel(); } } isSomeDate(date, compareDate) { if (date.getFullYear() !== compareDate.getFullYear()) { return false; } if (date.getMonth() !== compareDate.getMonth()) { return false; } if (date.getDate() !== compareDate.getDate()) { return false; } return true; } roundDate(date) { if (date.getHours() >= 12) { date.setDate(date.getDate() + 1); date.setHours(0, 0, 0); } else if (date.getHours() < 12) { date.setHours(0, 0, 0); } } unRegistContainerEvents() { } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: GanttService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); } static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: GanttService }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: GanttService, decorators: [{ type: Injectable }], ctorParameters: () => [] }); class GanttBarParentComponent { constructor(cdr, ganttService) { this.cdr = cdr; this.ganttService = ganttService; this.progressRate = 0; this.tipHovered = false; this.left = 0; this.width = 0; this.max = 100; this.min = 0; } ngOnInit() { if (this.progressRate === null) { this.setValue(this.ensureValueInRange(null)); } this.duration = this.ganttService.getDuration(this.startDate, this.endDate) + 'd'; this.ganttScaleStatusHandler = this.ganttService.ganttScaleConfigChange.subscribe((config) => { if (config.startDate) { this.left = this.ganttService.getDatePostionOffset(this.startDate); } if (config.unit) { this.left = this.ganttService.getDatePostionOffset(this.startDate); this.width = this.ganttService.getDurationWidth(this.startDate, this.endDate); } }); } ngOnChanges(changes) { const { progressRate, startDate, endDate } = changes; if (progressRate && this.progressRate > 0) { this.updateTrackAndHandle(); } if (startDate) { this.left = this.ganttService.getDatePostionOffset(this.startDate); this.width = this.ganttService.getDurationWidth(this.startDate, this.endDate); } if (endDate) { this.width = this.ganttService.getDurationWidth(this.startDate, this.endDate); } } ngAfterViewInit() { if (this.progressRate && this.progressRate > 0) { this.updateTrackAndHandle(); } } setValue(value) { if (this.progressRate !== value) { this.progressRate = value; this.updateTrackAndHandle(); } } ensureValueInRange(value) { let safeValue; if (!this.valueMustBeValid(value)) { safeValue = this.min; } else { safeValue = this.clamp(this.min, value, this.max); } return safeValue; } valueMustBeValid(value) { return !isNaN(typeof value !== 'number' ? parseFloat(value) : value); } clamp(min, n, max) { return Math.max(min, Math.min(n, max)); } updateTrackAndHandle() { const value = this.progressRate; const offset = this.valueToOffset(value); this.updateStyle(offset / 100); this.cdr.markForCheck(); } valueToOffset(value) { return ((value - this.min) / (this.max - this.min)) * 100; } updateStyle(percentage) { this.percentage = Math.min(1, Math.max(0, percentage)); if (this.ganttBarTrack && this.ganttBarTrack.nativeElement) { this.ganttBarTrack.nativeElement.style.width = `${this.percentage * 100}%`; } if (this.ganttBarProgress && this.ganttBarProgress.nativeElement) { this.ganttBarProgress.nativeElement.style.left = `${this.percentage * 100}%`; } } ngOnDestroy() { if (this.ganttScaleStatusHandler) { this.ganttScaleStatusHandler.unsubscribe(); this.ganttScaleStatusHandler = null; } } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: GanttBarParentComponent, deps: [{ token: i0.ChangeDetectorRef }, { token: GanttService }], target: i0.ɵɵFactoryTarget.Component }); } static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: GanttBarParentComponent, selector: "d-gantt-bar-parent", inputs: { startDate: "startDate", endDate: "endDate", progressRate: "progressRate", data: "data", id: "id", tip: "tip" }, viewQueries: [{ propertyName: "ganttBarProgress", first: true, predicate: ["ganttBarProgress"], descendants: true }, { propertyName: "ganttBarTrack", first: true, predicate: ["ganttBarTrack"], descendants: true }, { propertyName: "ganttBarRail", first: true, predicate: ["ganttBarRail"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<div\n *ngIf=\"startDate && endDate\"\n #ganttBar\n class=\"devui-gantt-bar-parent\"\n [style.left]=\"left + 'px'\"\n [style.width]=\"width + 'px'\"\n dTooltip\n [content]=\"tip\"\n>\n <div class=\"devui-gantt-bar-rail\" #ganttBarRail></div>\n <div class=\"devui-gantt-bar-track\" [ngClass]=\"{ head: percentage > 0, tail: percentage === 1 }\" #ganttBarTrack></div>\n</div>\n", styles: [".devui-gantt-bar-parent{width:100%;box-sizing:border-box;height:24px;z-index:3;position:relative}.devui-gantt-bar-parent .devui-gantt-bar-rail{position:absolute;background:#eaecf0;height:12px;width:100%;margin-top:4px}.devui-gantt-bar-parent .devui-gantt-bar-rail:before{width:0;height:0;border:3px transparent solid;border-top-color:#eaecf0;border-left-color:#eaecf0;position:absolute;left:0;bottom:-6px;content:\"\"}.devui-gantt-bar-parent .devui-gantt-bar-rail:after{width:0;height:0;border:3px transparent solid;border-top-color:#eaecf0;border-right-color:#eaecf0;position:absolute;right:0;bottom:-6px;content:\"\"}.devui-gantt-bar-parent .devui-gantt-bar-track{position:absolute;background-color:#cacfd8;height:12px;margin-top:4px;width:0}.devui-gantt-bar-parent .devui-gantt-bar-track.head:before{width:0;height:0;border:3px transparent solid;border-top-color:#cacfd8;border-left-color:#cacfd8;position:absolute;left:0;bottom:-6px;content:\"\"}.devui-gantt-bar-parent .devui-gantt-bar-track.tail:after{width:0;height:0;border:3px transparent solid;border-top-color:#cacfd8;border-right-color:#cacfd8;position:absolute;right:0;bottom:-6px;content:\"\"}\n"], dependencies: [{ kind: "directive", type: i2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i3.TooltipDirective, selector: "[dTooltip]", inputs: ["content", "position", "showAnimation", "showAnimate", "mouseEnterDelay", "mouseLeaveDelay"], exportAs: ["dTooltip"] }] }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: GanttBarParentComponent, decorators: [{ type: Component, args: [{ selector: 'd-gantt-bar-parent', template: "<div\n *ngIf=\"startDate && endDate\"\n #ganttBar\n class=\"devui-gantt-bar-parent\"\n [style.left]=\"left + 'px'\"\n [style.width]=\"width + 'px'\"\n dTooltip\n [content]=\"tip\"\n>\n <div class=\"devui-gantt-bar-rail\" #ganttBarRail></div>\n <div class=\"devui-gantt-bar-track\" [ngClass]=\"{ head: percentage > 0, tail: percentage === 1 }\" #ganttBarTrack></div>\n</div>\n", styles: [".devui-gantt-bar-parent{width:100%;box-sizing:border-box;height:24px;z-index:3;position:relative}.devui-gantt-bar-parent .devui-gantt-bar-rail{position:absolute;background:#eaecf0;height:12px;width:100%;margin-top:4px}.devui-gantt-bar-parent .devui-gantt-bar-rail:before{width:0;height:0;border:3px transparent solid;border-top-color:#eaecf0;border-left-color:#eaecf0;position:absolute;left:0;bottom:-6px;content:\"\"}.devui-gantt-bar-parent .devui-gantt-bar-rail:after{width:0;height:0;border:3px transparent solid;border-top-color:#eaecf0;border-right-color:#eaecf0;position:absolute;right:0;bottom:-6px;content:\"\"}.devui-gantt-bar-parent .devui-gantt-bar-track{position:absolute;background-color:#cacfd8;height:12px;margin-top:4px;width:0}.devui-gantt-bar-parent .devui-gantt-bar-track.head:before{width:0;height:0;border:3px transparent solid;border-top-color:#cacfd8;border-left-color:#cacfd8;position:absolute;left:0;bottom:-6px;content:\"\"}.devui-gantt-bar-parent .devui-gantt-bar-track.tail:after{width:0;height:0;border:3px transparent solid;border-top-color:#cacfd8;border-right-color:#cacfd8;position:absolute;right:0;bottom:-6px;content:\"\"}\n"] }] }], ctorParameters: () => [{ type: i0.ChangeDetectorRef }, { type: GanttService }], propDecorators: { ganttBarProgress: [{ type: ViewChild, args: ['ganttBarProgress'] }], ganttBarTrack: [{ type: ViewChild, args: ['ganttBarTrack'] }], ganttBarRail: [{ type: ViewChild, args: ['ganttBarRail'] }], startDate: [{ type: Input }], endDate: [{ type: Input }], progressRate: [{ type: Input }], data: [{ type: Input }], id: [{ type: Input }], tip: [{ type: Input }] } }); class GanttBarComponent { constructor(cdr, ganttService, ele) { this.cdr = cdr; this.ganttService = ganttService; this.ele = ele; this.mouseMoveTimer = null; this.mouseLeaveTimer = null; this.barHovering = false; this.progressHovering = false; this.focused = false; this.MIN_WIDTH = 10; this.left = 0; this.width = 0; this.EARLYOFFSET = 3; this.cdkOverlayOffsetX = 0; this.max = 100; this.min = 0; this.step = 1; this.mouseEventDalay = 100; this.tipHovered = false; this.mouseMoveOnBar = false; this.movedOut = false; this.scrollTimer = null; this.SCROLL_STEP = 10; this.outDirection = 'right'; this.scrollViewRange = [0, 0]; this.barMoveDisabled = false; this.barResizeDisabled = false; this.progressDisabled = false; this.progressRate = 0; this.originOffsetX = 0; this.showTitle = false; this.customBarClass = ''; this.customBgClass = ''; this.customTitleClass = ''; this.status = 'normal'; this.barMoveStartEvent = new EventEmitter(); this.barMovingEvent = new EventEmitter(); this.barMoveEndEvent = new EventEmitter(); this.barResizeStartEvent = new EventEmitter(); this.barResizingEvent = new EventEmitter(); this.barResizeEndEvent = new EventEmitter(); this.barProgressEvent = new EventEmitter(); this.onTouchedCallback = (v) => { }; this.onChangeCallback = (v) => { }; } ngOnInit() { this.checkRangeValues(this.min, this.max); this.checkStepValue(); if (this.progressRate === null) { this.setValue(this.ensureValueInRange(null)); } this.originStartDate = this.startDate; this.originEndDate = this.endDate; this.duration = this.ganttService.getDuration(this.startDate, this.endDate) + 'd'; this.ganttScaleStatusHandler = this.ganttService.ganttScaleConfigChange.subscribe((config) => { if (config.startDate) { this.left = this.ganttService.getDatePostionOffset(this.startDate); } if (config.unit) { this.left = this.ganttService.getDatePostionOffset(this.startDate); this.width = this.ganttService.getDurationWidth(this.startDate, this.endDate); } }); } ngOnChanges(changes) { const { progressRate, startDate, endDate, barMoveDisabled, barResizeDisabled, progressDisabled } = changes; if (Object.prototype.hasOwnProperty.call(changes, 'min') || Object.prototype.hasOwnProperty.call(changes, 'max') || Object.prototype.hasOwnProperty.call(changes, 'step')) { this.checkRangeValues(this.min, this.max); this.checkStepValue(); } if (progressRate && this.progressRate >= 0) { this.updateTrackAndHandle(); } if (startDate) { this.left = this.ganttService.getDatePostionOffset(this.startDate); this.width = this.ganttService.getDurationWidth(this.startDate, this.endDate); } if (endDate) { this.width = this.ganttService.getDurationWidth(this.startDate, this.endDate); } if (barMoveDisabled) { if (this.barMoveDisabled) { this.unsubscribeMouseActions(['start'], ['barMove']); } else { this.subscribeMouseActions(['start'], ['barMove']); } } if (barResizeDisabled) { if (this.barResizeDisabled) { this.unsubscribeMouseActions(['start'], ['barResize']); } else { this.subscribeMouseActions(['start'], ['barResize']); } } if (progressDisabled) { if (this.progressDisabled) { this.unsubscribeMouseActions(['start'], ['progress']); } else { this.subscribeMouseActions(['start'], ['progress']); } } } ngAfterViewInit() { if (this.startDate && this.endDate) { this.registerMouseEventsListeners(); this.registerHandleHoverPopoverListener(); if (!this.barMoveDisabled) { this.subscribeMouseActions(['start'], ['barMove']); } if (!this.barResizeDisabled) { this.subscribeMouseActions(['start'], ['barResize']); } if (!this.progressDisabled) { this.subscribeMouseActions(['start'], ['progress']); } } if (this.progressRate && this.progressRate > 0) { this.updateTrackAndHandle(); } } registerOnChange(fn) { this.onChangeCallback = fn; } registerOnTouched(fn) { this.onTouchedCallback = fn; } writeValue(newValue) { this.setValue(this.ensureValueInRange(newValue)); } checkRangeValues(minValue, maxValue) { if (maxValue <= minValue) { throw new Error(`max value must be greater than min value`); } } checkStepValue() { if (this.step < 0 || !this.step) { throw new Error('step value must be greater than 0.'); } else if ((this.max - this.min) % this.step) { throw new Error('(max - min) must be divisible by step.'); } } ratioToValue(ratio, min, max, step) { let value = (max - min) * ratio + min; if (step > 0) { value = Math.round(value / step) * step; } return this.clamp(min, value, max); } convertHandlePositionToRatio(handleX, startX, totalLength) { return this.clamp(0, (handleX - startX) / totalLength, 1); } clamp(min, n, max) { return Math.max(min, Math.min(n, max)); } updateStyle(percentage) { this.percentage = Math.min(1, Math.max(0, percentage)); if (this.ganttBarTrack && this.ganttBarTrack.nativeElement) { this.ganttBarTrack.nativeElement.style.width = `${this.percentage * 100}%`; } if (this.ganttBarProgress && this.ganttBarProgress.nativeElement) { this.ganttBarProgress.nativeElement.style.left = `${this.percentage * 100}%`; } } registerMouseEventsListeners() { this.moveBarStartListener = fromEvent(this.ganttBarMain.nativeElement, 'mousedown').pipe(tap((e) => { e.stopPropagation(); e.preventDefault(); }), pluck('pageX')); this.dragProgressStartListener = fromEvent(this.ganttBarProgress.nativeElement, 'mousedown').pipe(tap((e) => { e.stopPropagation(); e.preventDefault(); }), pluck('pageX'), map((position) => this.mousePositionToAdaptiveValue(position))); this.resizeBarLeftStartListener = fromEvent(this.ganttBarDarggerLeft.nativeElement, 'mousedown').pipe(tap((e) => { e.stopPropagation(); e.preventDefault(); }), pluck('pageX')); this.resizeBarRightStartListener = fromEvent(this.ganttBarDarggerRight.nativeElement, 'mousedown').pipe(tap((e) => { e.stopPropagation(); e.preventDefault(); }), pluck('pageX')); this.mouseEndListener = fromEvent(document, 'mouseup'); this.mouseMoveListener = fromEvent(document, 'mousemove').pipe(tap((e) => { e.stopPropagation(); e.preventDefault(); }), pluck('pageX'), distinctUntilChanged(), takeUntil(this.mouseEndListener)); } getSliderPagePosition() { const rect = this.ganttBar.nativeElement.getBoundingClientRect(); const window = this.ganttBar.nativeElement.ownerDocument.defaultView; return rect.left + window.pageXOffset; } getRailLength() { return this.ganttBarRail.nativeElement.clientWidth; } mousePositionToAdaptiveValue(handleX) { const sliderStartX = this.getSliderPagePosition(); const sliderLength = this.getRailLength(); const ratio = this.convertHandlePositionToRatio(handleX, sliderStartX, sliderLength); const value = this.ratioToValue(ratio, this.min, this.max, this.step); return parseFloat(value.toFixed(this.getDecimals(this.step))); } getDecimals(value) { const valueString = value.toString(); const integerLength = valueString.indexOf('.') + 1; return integerLength >= 0 ? valueString.length - integerLength : 0; } progressStartDrag(value) { this.dragProgressStart = true; this.handleController(true); this.setValue(value); } barStartMoving(value) { this.scrollViewRange = [ this.scrollElement.getBoundingClientRect().left + this.originOffsetX, this.scrollElement.getBoundingClientRect().right, ]; this.moveBarStart = true; this.barMoveStartPageX = value; this.barOriginLeft = parseInt(this.ganttBar.nativeElement.style.left, 10); this.handleController(true); this.barMoveStartEvent.emit(this.getGanttTaskInfo()); } barLeftStartResizing(value) { this.resizeBarLeftStart = true; this.barResizeStartPageX = value; this.barOriginLeft = parseInt(this.ganttBar.nativeElement.style.left, 10); this.barOriginWidth = this.ganttBar.nativeElement.style.width; this.handleController(true); this.barResizeStartEvent.emit(this.getGanttTaskInfo()); } barRightStartResizing(value) { this.resizeBarRightStart = true; this.barResizeStartPageX = value; this.barOriginLeft = parseInt(this.ganttBar.nativeElement.style.left, 10); this.barOriginWidth = this.ganttBar.nativeElement.style.width; this.handleController(true); this.barResizeStartEvent.emit(this.getGanttTaskInfo()); } mouseMoving(value) { if (this.dragProgressStart) { this.setValue(this.mousePositionToAdaptiveValue(value)); this.cdr.markForCheck(); } if (this.resizeBarLeftStart) { this.mouseMoveOnBar = true; const offset = value - this.barResizeStartPageX; const finalWidth = parseInt(this.barOriginWidth, 10) - Math.round(offset); if (finalWidth < this.MIN_WIDTH) { return; } const timeOffset = Math.round((offset / this.ganttService.getScaleUnitPixel()) * GanttService.DAY_DURATION); this.startDate = new Date(this.originStartDate.getTime() + timeOffset); this.ganttService.roundDate(this.startDate); if (this.endDate < this.startDate) { this.startDate = this.endDate; } const earlyDateTime = this.startDate.getTime() - this.EARLYOFFSET * GanttService.DAY_DURATION; if (offset < 0 && earlyDateTime < this.ganttService.scaleStartDate.getTime()) { this.ganttService.setScaleConfig({ startDate: new Date(earlyDateTime) }); this.barOriginLeft = this.EARLYOFFSET * this.ganttService.getScaleUnitPixel() - Math.round(offset); } const finalLeft = this.barOriginLeft + Math.round(offset); this.left = finalLeft; this.width = finalWidth; this.dispatchGanttBarStatus(); const info = this.getGanttTaskInfo(); info.moveOffset = offset; this.barResizingEvent.emit(info); } if (this.resizeBarRightStart) { this.mouseMoveOnBar = true; const offset = value - this.barResizeStartPageX; const finalWidth = parseInt(this.barOriginWidth, 10) + Math.round(offset); if (finalWidth < this.MIN_WIDTH) { return; } const timeOffset = Math.round((offset / this.ganttService.getScaleUnitPixel()) * GanttService.DAY_DURATION); this.endDate = new Date(this.originEndDate.getTime() + timeOffset); this.ganttService.roundDate(this.endDate); if (this.endDate < this.startDate) { this.endDate = this.startDate; } const lateDateTime = this.endDate.getTime() + this.EARLYOFFSET * GanttService.DAY_DURATION; if (offset > 0 && lateDateTime > this.ganttService.scaleEndDate.getTime()) { this.ganttService.setScaleConfig({ endDate: new Date(lateDateTime) }); } this.width = finalWidth; this.dispatchGanttBarStatus(); const info = this.getGanttTaskInfo(); info.moveOffset = offset; this.barResizingEvent.emit(info); } if (this.moveBarStart) { this.checkIsOut(value); if (this.movedOut) { return; } this.mouseMoveOnBar = true; const offset = value - this.barMoveStartPageX; const timeOffset = Math.round((Math.round(offset) / this.ganttService.getScaleUnitPixel()) * GanttService.DAY_DURATION); const newStartDate = new Date(this.originStartDate.getTime() + timeOffset); this.ganttService.roundDate(newStartDate); this.startDate = newStartDate; const newEndDate = new Date(this.originEndDate.getTime() + timeOffset); this.ganttService.roundDate(newEndDate); this.endDate = newEndDate; const earlyDateTime = this.startDate.getTime() - this.EARLYOFFSET * GanttService.DAY_DURATION; const lateDateTime = this.endDate.getTime() + this.EARLYOFFSET * GanttService.DAY_DURATION; if (earlyDateTime < this.ganttService.scaleStartDate.getTime()) { this.ganttService.setScaleConfig({ startDate: new Date(earlyDateTime) }); } else if (lateDateTime > this.ganttService.scaleEndDate.getTime()) { this.ganttService.setScaleConfig({ endDate: new Date(lateDateTime) }); } const finalLeft = this.barOriginLeft + Math.round(offset); this.left = finalLeft; this.dispatchGanttBarStatus(); const info = this.getGanttTaskInfo(); info.moveOffset = offset; this.barMovingEvent.emit(info); } } checkIsOut(value) { this.outDirection = value - this.barMoveStartPageX > 0 ? 'right' : 'left'; if (this.outDirection === 'left') { this.movedOut = value < this.scrollViewRange[0]; } else { this.movedOut = value > this.scrollViewRange[1]; } if (this.movedOut) { this.autoScroll(); } else if (this.scrollTimer) { const left = this.outDirection === 'left' ? this.scrollElement.scrollLeft + (value - this.scrollElement.getBoundingClientRect().left) - this.originOffsetX : this.scrollElement.scrollLeft + this.scrollElement.clientWidth - this.originOffsetX; this.setLeft(Math.round(left)); this.stopAutoScroll(); this.barMoveStartPageX = value; } } autoScroll() { if (!this.scrollTimer) { this.scrollTimer = setInterval(() => { this.outDirection === 'left' ? (this.scrollElement.scrollLeft -= this.SCROLL_STEP) : (this.scrollElement.scrollLeft += this.SCROLL_STEP); }, 10); } } stopAutoScroll() { clearInterval(this.scrollTimer); this.scrollTimer = null; } setLeft(left) { const offset = left - this.left; const timeOffset = (Math.round(offset) / this.ganttService.getScaleUnitPixel()) * GanttService.DAY_DURATION; const newStartDate = new Date(this.startDate.getTime() + timeOffset); this.ganttService.roundDate(newStartDate); this.startDate = newStartDate; const newEndDate = new Date(this.endDate.getTime() + timeOffset); this.ganttService.roundDate(newEndDate); this.endDate = newEndDate; this.originStartDate = this.startDate; this.originEndDate = this.endDate; this.barOriginLeft = left; this.left = left; } getGanttTaskInfo() { this.duration = this.ganttService.getDuration(this.startDate, this.endDate) + 'd'; const progress = this.progressRate + '%'; const taskInfo = { id: this.id, startDate: this.startDate, endDate: this.endDate, duration: this.duration, progress: progress, left: this.left, width: this.width, }; return taskInfo; } mouseStopMoving() { this.mouseMoveOnBar = false; this.ganttService.roundDate(this.startDate); this.ganttService.roundDate(this.endDate); this.originStartDate = this.startDate; this.originEndDate = this.endDate; const taskInfo = this.getGanttTaskInfo(); if (this.moveBarStart) { const finalLeft = this.ganttService.getDatePostionOffset(this.startDate); this.left = finalLeft > 0 ? finalLeft : 0; this.barMoveEndEvent.emit(taskInfo); } if (this.resizeBarLeftStart) { const finalLeft = this.ganttService.getDatePostionOffset(this.startDate); const finalWidth = this.ganttService.getDurationWidth(this.startDate, this.endDate); this.left = finalLeft > 0 ? finalLeft : 0; this.width = finalWidth; this.barResizeEndEvent.emit(taskInfo); } if (this.resizeBarRightStart) { const finalWidth = this.ganttService.getDurationWidth(this.startDate, this.endDate); this.width = finalWidth; this.barResizeEndEvent.emit(taskInfo); } if (this.dragProgressStart) { this.barProgressEvent.emit(this.progressRate); } this.handleController(false); this.stopAutoScroll(); this.cdr.markForCheck(); } subscribeMouseActions(mouseActions = ['start', 'move', 'end'], events = ['barMove', 'barResize', 'progress']) { if (mouseActions.indexOf('start') !== -1 && this.dragProgressStartListener && !this.dragProgressStartHandler && events.indexOf('progress') !== -1) { this.dragProgressStartHandler = this.dragProgressStartListener.subscribe(this.progressStartDrag.bind(this)); } if (mouseActions.indexOf('start') !== -1 && this.moveBarStartListener && !this.moveBarStartHandler && events.indexOf('barMove') !== -1) { this.moveBarStartHandler = this.moveBarStartListener.subscribe(this.barStartMoving.bind(this)); } if (mouseActions.indexOf('start') !== -1 && this.resizeBarLeftStartListener && !this.resizeBarLeftStartHandler && events.indexOf('barResize') !== -1) { this.resizeBarLeftStartHandler = this.resizeBarLeftStartListener.subscribe(this.barLeftStartResizing.bind(this)); } if (mouseActions.indexOf('start') !== -1 && this.resizeBarRightStartListener && !this.resizeBarRightStartHandler && events.indexOf('barResize') !== -1) { this.resizeBarRightStartHandler = this.resizeBarRightStartListener.subscribe(this.barRightStartResizing.bind(this)); } if (mouseActions.indexOf('move') !== -1 && this.mouseMoveListener && !this.mouseMoveHandler) { this.mouseMoveHandler = this.mouseMoveListener.subscribe(this.mouseMoving.bind(this)); } if (mouseActions.indexOf('end') !== -1 && this.mouseEndListener && !this.mouseEndHandler) { this.mouseEndHandler = this.mouseEndListener.subscribe(this.mouseStopMoving.bind(this)); } } unsubscribeMouseActions(dragStages = ['start', 'move', 'end'], events = ['barMove', 'barResize', 'progress']) { if (dragStages.indexOf('start') !== -1 && events.indexOf('progress') !== -1 && this.dragProgressStartHandler) { this.dragProgressStartHandler.unsubscribe(); this.dragProgressStartHandler = null; } if (dragStages.indexOf('start') !== -1 && events.indexOf('barMove') !== -1 && this.moveBarStartHandler) { this.moveBarStartHandler.unsubscribe(); this.moveBarStartHandler = null; } if (dragStages.indexOf('start') !== -1 && events.indexOf('barResize') !== -1 && this.resizeBarLeftStartHandler) { this.resizeBarLeftStartHandler.unsubscribe(); this.resizeBarLeftStartHandler = null; } if (dragStages.indexOf('start') !== -1 && events.indexOf('barResize') !== -1 && this.resizeBarRightStartHandler) { this.resizeBarRightStartHandler.unsubscribe(); this.resizeBarRightStartHandler = null; } if (dragStages.indexOf('move') !== -1 && this.mouseMoveHandler) { this.mouseMoveHandler.unsubscribe(); this.mouseMoveHandler = null; } if (dragStages.indexOf('end') !== -1 && this.mouseEndHandler) { this.mouseEndHandler.unsubscribe(); this.mouseEndHandler = null; } } handleController(movable) { if (movable) { this.focused = this.focusController(); this.subscribeMouseActions(['move', 'end']); } else { this.dragProgressStart = false; this.moveBarStart = false; this.resizeBarLeftStart = false; this.resizeBarRightStart = false; this.focused = this.focusController(); this.unsubscribeMouseActions(['move', 'end']); } } setValue(value) { if (this.progressRate !== value) { this.progressRate = value; this.updateTrackAndHandle(); } this.onChangeCallback(this.progressRate); } ensureValueInRange(value) { let safeValue; if (!this.valueMustBeValid(value)) { safeValue = this.min; } else { safeValue = this.clamp(this.min, value, this.max); } return safeValue; } updateTrackAndHandle() { const value = this.progressRate; const offset = this.valueToOffset(value); this.updateStyle(offset / 100); this.cdr.markForCheck(); } valueMustBeValid(value) { return !isNaN(typeof value !== 'number' ? parseFloat(value) : value); } valueToOffset(value) { return ((value - this.min) / (this.max - this.min)) * 100; } registerHandleHoverPopoverListener() { const mouseOverProgressListener = fromEvent(this.ganttBarProgress.nativeElement, 'mouseover'); const mouseLeaveProgressListener = fromEvent(this.ganttBarProgress.nativeElement, 'mouseout'); this.mouseOverProgressHandler = mouseOverProgressListener.subscribe(this.ganttProgressPopoverOnMouseHover.bind(this)); this.mouseLeaveProgressHandler = mouseLeaveProgressListener.subscribe(this.ganttProgressPopoverOnMouseLeave.bind(this)); } ganttBarPopoverOnMouseHover($event) { if (this.mouseLeaveTimer) { clearTimeout(this.mouseLeaveTimer); } this.mouseMoveTimer = setTimeout(() => { const barLeft = this.ganttBar.nativeElement.getClientRects()[0].left; const eventLeft = $event.clientX; this.cdkOverlayOffsetX = eventLeft - barLeft; this.barHovering = true; this.focused = this.focusController(); this.dispatchGanttBarStatus(); this.cdr.markForCheck(); }, this.mouseEventDalay); } ganttBarPopoverOnMouseLeave() { if (this.mouseMoveTimer) { clearTimeout(this.mouseMoveTimer); } this.mouseLeaveTimer = setTimeout(() => { this.barHovering = false; this.focused = this.focusController(); this.dispatchGanttBarStatus(); this.cdr.markForCheck(); }, this.mouseEventDalay); } mouseLeaveTip() { setTimeout(() => { this.tipHovered = false; }, this.mouseEventDalay); } ganttProgressPopoverOnMouseHover() { this.progressHovering = true; } ganttProgressPopoverOnMouseLeave() { this.progressHovering = false; } unregisterHandleHoverTooltip() { if (this.mouseOverProgressHandler) { this.mouseOverProgressHandler.unsubscribe(); this.mouseOverProgressHandler = null; } if (this.mouseLeaveProgressHandler) { this.mouseLeaveProgressHandler.unsubscribe(); this.mouseLeaveProgressHandler = null; } } clearTimer() { if (this.mouseLeaveTimer) { clearTimeout(this.mouseLeaveTimer); } if (this.mouseMoveTimer) { clearTimeout(this.mouseMoveTimer); } } focusController() { return this.dragProgressStart || this.moveBarStart || this.resizeBarLeftStart || this.resizeBarRightStart || this.barHovering; } dispatchGanttBarStatus() { const status = { focused: this.focused, startDate: this.startDate, endDate: this.endDate, }; this.ganttService.changeGanttBarStatus(status); } ngOnDestroy() { this.clearTimer(); this.unsubscribeMouseActions(); this.unregisterHandleHoverTooltip(); if (this.ganttScaleStatusHandler) { this.ganttScaleStatusHandler.unsubscribe(); this.ganttScaleStatusHandler = null; } } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: GanttBarComponent, deps: [{ token: i0.ChangeDetectorRef }, { token: GanttService }, { token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Component }); } static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: GanttBarComponent, selector: "d-gantt-bar", inputs: { barMoveDisabled: "barMoveDisabled", barResizeDisabled: "barResizeDisabled", progressDisabled: "progressDisabled", startDate: "startDate", endDate: "endDate", progressRate: "progressRate", tipTemplateRef: "tipTemplateRef", titleTemplateRef: "titleTemplateRef", data: "data", originOffsetX: "originOffsetX", id: "id", title: "title", showTitle: "showTitle", customBarClass: "customBarClass", customBgClass: "customBgClass", customTitleClass: "customTitleClass", scrollElement: "scrollElement", status: "status" }, outputs: { barMoveStartEvent: "barMoveStartEvent", barMovingEvent: "barMovingEvent", barMoveEndEvent: "barMoveEndEvent", barResizeStartEvent: "barResizeStartEvent", barResizingEvent: "barResizingEvent", barResizeEndEvent: "barResizeEndEvent", barProgressEvent: "barProgressEvent" }, viewQueries: [{ propertyName: "ganttBar", first: true, predicate: ["ganttBar"], descendants: true }, { propertyName: "ganttBarMain", first: true, predicate: ["ganttBarMain"], descendants: true }, { propertyName: "ganttBarProgress", first: true, predicate: ["ganttBarProgress"], descendants: true }, { propertyName: "ganttBarTrack", first: true, predicate: ["ganttBarTrack"], descendants: true }, { propertyName: "ganttBarRail", first: true, predicate: ["ganttBarRail"], descendants: true }, { propertyName: "ganttBarDarggerLeft", first: true, predicate: ["ganttBarDarggerLeft"], descendants: true }, { propertyName: "ganttBarDarggerRight", first: true, predicate: ["ganttBarDarggerRight"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<div\n *ngIf=\"startDate && endDate\"\n class=\"devui-gantt-bar {{ customBarClass }}\"\n #ganttBar\n cdk-overlay-origin\n #progress=\"cdkOverlayOrigin\"\n [style.left]=\"left + 'px'\"\n [style.width]=\"width + 'px'\"\n (mouseover)=\"ganttBarPopoverOnMouseHover($event)\"\n (mouseleave)=\"ganttBarPopoverOnMouseLeave()\"\n>\n <div class=\"devui-gantt-hover-layer\" [style.width]=\"width + 24 + 'px'\" [style.display]=\"focused ? 'block' : 'none'\">\n <div #ganttBarDarggerLeft class=\"devui-gantt-dragger left\">\n <div class=\"handle\" [ngClass]=\"{ disabled: barResizeDisabled }\"></div>\n </div>\n <div #ganttBarDarggerRight class=\"devui-gantt-dragger right\">\n <div class=\"handle\" [ngClass]=\"{ disabled: barResizeDisabled }\"></div>\n </div>\n </div>\n <div #ganttBarMain class=\"devui-gantt-main\" [ngClass]=\"{ disabled: barMoveDisabled }\">\n <div class=\"devui-gantt-bar-rail devui-gantt-bar-rail-{{ status }}\" #ganttBarRail></div>\n <div class=\"devui-gantt-bar-track devui-gantt-bar-track-{{ status }}\" #ganttBarTrack></div>\n </div>\n <div\n class=\"devui-gantt-bar-progress\"\n #ganttBarProgress\n [ngClass]=\"{ disabled: progressDisabled, visible: focused }\"\n [attr.title]=\"progressRate ? progressRate : 0 + '%'\"\n >\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n width=\"12px\"\n height=\"16px\"\n viewBox=\"0 0 12 16\"\n version=\"1.1\"\n >\n <g id=\"gantt-bar-handle\" stroke=\"none\" stroke-width=\"1\" fill=\"none\" fill-rule=\"evenodd\">\n <path\n d=\"M7.06066017,1.35355339 C6.76776695,1.06066017 6.38388348,0.914213562 6,0.914213562 C5.61611652,0.914213562 5.23223305,1.06066017 4.93933983,1.35355339 L0.5,5.79289322 L0.5,13 C0.5,13.6903559 0.779822031,14.3153559 1.23223305,14.767767 C1.68464406,15.220178 2.30964406,15.5 3,15.5 L9,15.5 C9.69035594,15.5 10.3153559,15.220178 10.767767,14.767767 C11.220178,14.3153559 11.5,13.6903559 11.5,13 L11.5,5.79289322 L7.06066017,1.35355339 Z\"\n stroke=\"none\"\n fill=\"none\"\n />\n </g>\n </svg>\n </div>\n <div class=\"devui-gantt-bar-title {{ customTitleClass }}\" *ngIf=\"showTitle\">\n <ng-container *ngIf=\"titleTemplateRef\">\n <ng-template [ngTemplateOutlet]=\"titleTemplateRef\" [ngTemplateOutletContext]=\"{ data: data }\"></ng-template>\n </ng-container>\n <ng-container *ngIf=\"!titleTemplateRef\">{{ title }}</ng-container>\n </div>\n <ng-template\n *ngIf=\"tipTemplateRef\"\n cdk-connected-overlay\n [cdkConnectedOverlayOffsetX]=\"cdkOverlayOffsetX\"\n [cdkConnectedOverlayOrigin]=\"progress\"\n [cdkConnectedOverlayOpen]=\"(focused || tipHovered) && !mouseMoveOnBar\"\n >\n <div class=\"devui-gantt-tips\" (mouseover)=\"tipHovered = true\" (mouseleave)=\"mouseLeaveTip()\">\n <ng-template [ngTemplateOutlet]=\"tipTemplateRef\" [ngTemplateOutletContext]=\"{ ganttInstance: this, data: data }\"></ng-template>\n </div>\n </ng-template>\n</div>\n\n<div\n *ngIf=\"moveBarStart\"\n class=\"moving-bg {{ customBgClass }}\"\n [style.left]=\"originOffsetX + left + 'px'\"\n [style.width]=\"width + 'px'\"\n></div>\n", styles: [":host{display:block}.devui-gantt-bar{position:relative;width:100%;cursor:pointer;box-sizing:border-box;height:24px;z-index:3}.devui-gantt-bar .devui-gantt-main{cursor:move}.devui-gantt-bar .devui-gantt-main.disabled{cursor:not-allowed}.devui-gantt-bar .devui-gantt-bar-rail-normal{background:#9dbdfc}.devui-gantt-bar .devui-gantt-bar-rail-overdue{background:#fabdc1}.devui-gantt-bar .devui-gantt-bar-rail-done{background:#dfdfdf}.devui-gantt-bar .devui-gantt-bar-rail{position:absolute;box-shadow:var(--devui-shadow-length-base, 0 1px 6px 0) #5170ff30;height:20px;margin-top:4px;width:100%;border-radius:var(--devui-border-radius, 2px)}.devui-gantt-bar .devui-gantt-bar-rail.disabled{background-color:var(--devui-area, #f3f3f3)}.devui-gantt-bar .devui-gantt-hover-layer{display:none;position:absolute;height:24px;top:2px;left:-12px;border-radius:var(--devui-border-radius, 2px);background-color:var(--devui-connected-overlay-bg, #ffffff);box-shadow:var(--devui-shadow-length-hover, 0 8px 24px 0) #5170ff4d}.devui-gantt-bar .devui-gantt-hover-layer .devui-gantt-dragger{position:absolute;width:12px;height:24px;cursor:col-resize;display:flex;align-items:center}.devui-gantt-bar .devui-gantt-hover-layer .devui-gantt-dragger.left{left:0}.devui-gantt-bar .devui-gantt-hover-layer .devui-gantt-dragger.right{right:0}.devui-gantt-bar .devui-gantt-hover-layer .devui-gantt-dragger .handle{width:2px;height:14px;background:var(--devui-icon-fill, #595959);border-radius:var(--devui-border-radius, 2px);margin:4px}.devui-gantt-bar .devui-gantt-hover-layer .devui-gantt-dragger .handle.disabled{cursor:not-allowed}.devui-gantt-bar .devui-gantt-bar-track-overdue{background-color:var(--devui-danger, #e02128)}.devui-gantt-bar .devui-gantt-bar-track-done{background-color:#939393}.devui-gantt-bar .devui-gantt-bar-track-normal{background-color:var(--devui-brand, #0a59f7);box-shadow:var(--devui-shadow-length-base, 0 1px 6px 0) #5170ff66}.devui-gantt-bar .devui-gantt-bar-track{position:absolute;border-radius:var(--devui-border-radius, 2px) 0 0 var(--devui-border-radius, 2px);height:20px;margin-top:4px;width:0}.devui-gantt-bar .devui-gantt-bar-progress{display:none;position:absolute;left:0;bottom:-8px;transform:translate(-50%);cursor:pointer}.devui-gantt-bar .devui-gantt-bar-progress>svg{display:block}.devui-gantt-bar .devui-gantt-bar-progress>svg>g>path{fill:var(--devui-icon-bg, #ffffff);stroke:var(--devui-icon-fill-active, #191919)}.devui-gantt-bar .devui-gantt-bar-progress.visible{display:block}.devui-gantt-bar .devui-gantt-bar-progress.disabled{cursor:not-allowed}.devui-gantt-bar:hover .devui-gantt-bar-progress{display:block}.devui-gantt-bar .devui-gantt-bar-title{position:absolute;display:inline-flex;align-items:center;left:100%;height:100%;margin-left:12px;word-break:keep-all}.devui-gantt-tips{width:280px;min-height:100px;background:var(--devui-base-bg, #ffffff);box-shadow:var(--devui-shadow-length-feedback-overlay, 0 8px 24px 0) #5170ff1a;border-radius:var(--devui-border-radius-card, 6px);padding:16px;margin-top:8px}.moving-bg{position:absolute;height:100%;top:0;bottom:0;background:var(--devui-float-block-shadow, rgba(94, 124, 224, .3));opacity:.3}\n"], dependencies: [{ kind: "directive", type: i2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i2.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i3$1.CdkConnectedOverlay, selector: "[cdk-connected-overlay], [connected-overlay], [cdkConnectedOverlay]", inputs: ["cdkConnectedOverlayOrigin", "cdkConnectedOverlayPositions", "cdkConnectedOverlayPositionStrategy", "cdkConnectedOverlayOffsetX", "cdkConnectedOverlayOffsetY", "cdkConnectedOverlayWidth", "cdkConnectedOverlayHeight", "cdkConnectedOverlayMinWidth", "cdkConnectedOverlayMinHeight", "cdkConnectedOverlayBackdropClass", "cdkConnectedOverlayPanelClass", "cdkConnectedOverlayViewportMargin", "cdkConnectedOverlayScrollStrategy", "cdkConnectedOverlayOpen", "cdkConnectedOverlayDisableClose", "cdkConnectedOverlayTransformOriginOn", "cdkConnectedOverlayHasBackdrop", "cdkConnectedOverlayLockPosition", "cdkConnectedOverlayFlexibleDimensions", "cdkConnectedOverlayGrowAfterOpen", "cdkConnectedOverlayPush", "cdkConnectedOverlayDisposeOnNavigation"], outputs: ["backdropClick", "positionChange", "attach", "detach", "overlayKeydown", "overlayOutsideClick"], exportAs: ["cdkConnectedOverlay"] }, { kind: "directive", type: i3$1.CdkOverlayOrigin, selector: "[cdk-overlay-origin], [overlay-origin], [cdkOverlayOrigin]", exportAs: ["cdkOverlayOrigin"] }] }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: GanttBarComponent, decorators: [{ type: Component, args: [{ selector: 'd-gantt-bar', template: "<div\n *ngIf=\"startDate && endDate\"\n class=\"devui-gantt-bar {{ customBarClass }}\"\n #ganttBar\n cdk-overlay-origin\n #progress=\"cdkOverlayOrigin\"\n [style.left]=\"left + 'px'\"\n [style.width]=\