diff --git a/package-lock.json b/package-lock.json index 7dacaa59..267c434a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6716,9 +6716,9 @@ } }, "node_modules/ajv-formats/node_modules/ajv": { - "version": "8.11.2", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.2.tgz", - "integrity": "sha512-E4bfmKAhGiSTvMfL1Myyycaub+cUEU2/IvpylXkUu7CHBkBj1f/ikdzbD7YQ6FKUbixDxeYvB/xY4fvyroDlQg==", + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", "dev": true, "dependencies": { "fast-deep-equal": "^3.1.1", @@ -9762,9 +9762,9 @@ } }, "node_modules/copy-webpack-plugin/node_modules/ajv": { - "version": "8.11.2", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.2.tgz", - "integrity": "sha512-E4bfmKAhGiSTvMfL1Myyycaub+cUEU2/IvpylXkUu7CHBkBj1f/ikdzbD7YQ6FKUbixDxeYvB/xY4fvyroDlQg==", + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", "dev": true, "dependencies": { "fast-deep-equal": "^3.1.1", @@ -17168,9 +17168,9 @@ } }, "node_modules/mini-css-extract-plugin/node_modules/ajv": { - "version": "8.11.2", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.2.tgz", - "integrity": "sha512-E4bfmKAhGiSTvMfL1Myyycaub+cUEU2/IvpylXkUu7CHBkBj1f/ikdzbD7YQ6FKUbixDxeYvB/xY4fvyroDlQg==", + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", "dev": true, "dependencies": { "fast-deep-equal": "^3.1.1", @@ -17642,9 +17642,9 @@ } }, "node_modules/ng-packagr/node_modules/ajv": { - "version": "8.11.2", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.2.tgz", - "integrity": "sha512-E4bfmKAhGiSTvMfL1Myyycaub+cUEU2/IvpylXkUu7CHBkBj1f/ikdzbD7YQ6FKUbixDxeYvB/xY4fvyroDlQg==", + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", "dev": true, "dependencies": { "fast-deep-equal": "^3.1.1", @@ -24295,9 +24295,9 @@ } }, "node_modules/webpack-dev-middleware/node_modules/ajv": { - "version": "8.11.2", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.2.tgz", - "integrity": "sha512-E4bfmKAhGiSTvMfL1Myyycaub+cUEU2/IvpylXkUu7CHBkBj1f/ikdzbD7YQ6FKUbixDxeYvB/xY4fvyroDlQg==", + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", "dev": true, "dependencies": { "fast-deep-equal": "^3.1.1", @@ -24397,9 +24397,9 @@ } }, "node_modules/webpack-dev-server/node_modules/ajv": { - "version": "8.11.2", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.2.tgz", - "integrity": "sha512-E4bfmKAhGiSTvMfL1Myyycaub+cUEU2/IvpylXkUu7CHBkBj1f/ikdzbD7YQ6FKUbixDxeYvB/xY4fvyroDlQg==", + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", "dev": true, "dependencies": { "fast-deep-equal": "^3.1.1", @@ -29749,9 +29749,9 @@ }, "dependencies": { "ajv": { - "version": "8.11.2", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.2.tgz", - "integrity": "sha512-E4bfmKAhGiSTvMfL1Myyycaub+cUEU2/IvpylXkUu7CHBkBj1f/ikdzbD7YQ6FKUbixDxeYvB/xY4fvyroDlQg==", + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", "dev": true, "requires": { "fast-deep-equal": "^3.1.1", @@ -32144,9 +32144,9 @@ }, "dependencies": { "ajv": { - "version": "8.11.2", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.2.tgz", - "integrity": "sha512-E4bfmKAhGiSTvMfL1Myyycaub+cUEU2/IvpylXkUu7CHBkBj1f/ikdzbD7YQ6FKUbixDxeYvB/xY4fvyroDlQg==", + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", "dev": true, "requires": { "fast-deep-equal": "^3.1.1", @@ -37762,9 +37762,9 @@ }, "dependencies": { "ajv": { - "version": "8.11.2", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.2.tgz", - "integrity": "sha512-E4bfmKAhGiSTvMfL1Myyycaub+cUEU2/IvpylXkUu7CHBkBj1f/ikdzbD7YQ6FKUbixDxeYvB/xY4fvyroDlQg==", + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", "dev": true, "requires": { "fast-deep-equal": "^3.1.1", @@ -38136,9 +38136,9 @@ }, "dependencies": { "ajv": { - "version": "8.11.2", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.2.tgz", - "integrity": "sha512-E4bfmKAhGiSTvMfL1Myyycaub+cUEU2/IvpylXkUu7CHBkBj1f/ikdzbD7YQ6FKUbixDxeYvB/xY4fvyroDlQg==", + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", "dev": true, "requires": { "fast-deep-equal": "^3.1.1", @@ -43198,9 +43198,9 @@ }, "dependencies": { "ajv": { - "version": "8.11.2", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.2.tgz", - "integrity": "sha512-E4bfmKAhGiSTvMfL1Myyycaub+cUEU2/IvpylXkUu7CHBkBj1f/ikdzbD7YQ6FKUbixDxeYvB/xY4fvyroDlQg==", + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", "dev": true, "requires": { "fast-deep-equal": "^3.1.1", @@ -43270,9 +43270,9 @@ }, "dependencies": { "ajv": { - "version": "8.11.2", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.2.tgz", - "integrity": "sha512-E4bfmKAhGiSTvMfL1Myyycaub+cUEU2/IvpylXkUu7CHBkBj1f/ikdzbD7YQ6FKUbixDxeYvB/xY4fvyroDlQg==", + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", "dev": true, "requires": { "fast-deep-equal": "^3.1.1", diff --git a/packages/gantt/src/components/bar/bar-drag.ts b/packages/gantt/src/components/bar/bar-drag.ts index 387d3e2c..d4da7831 100644 --- a/packages/gantt/src/components/bar/bar-drag.ts +++ b/packages/gantt/src/components/bar/bar-drag.ts @@ -91,6 +91,7 @@ export class GanttBarDrag implements OnDestroy { private createBarDrag() { const dragRef = this.dragDrop.createDrag(this.barElement); dragRef.lockAxis = 'x'; + dragRef.withBoundaryElement(this.dom.mainItems as HTMLElement); dragRef.started.subscribe(() => { this.setDraggingStyles(); this.dragContainer.dragStarted.emit({ item: this.item.origin }); @@ -109,7 +110,7 @@ export class GanttBarDrag implements OnDestroy { start = start.addDays(1); end = end.addDays(1); } - // this.openDragBackdrop(this.barElement, start, end); + this.openDragBackdrop( this.barElement, this.ganttUpper.view.getDateByXPoint(currentX), @@ -136,7 +137,7 @@ export class GanttBarDrag implements OnDestroy { const isBefore = index === 0; const dragRef = this.dragDrop.createDrag(handle); dragRef.lockAxis = 'x'; - dragRef.withBoundaryElement(this.dom.root as HTMLElement); + dragRef.withBoundaryElement(this.dom.mainItems as HTMLElement); dragRef.started.subscribe(() => { this.setDraggingStyles(); @@ -147,23 +148,21 @@ export class GanttBarDrag implements OnDestroy { if (isBefore) { const x = this.item.refs.x + event.distance.x; const width = this.item.refs.width + event.distance.x * -1; + const start = this.ganttUpper.view.getDateByXPoint(x); if (width > dragMinWidth) { this.barElement.style.width = width + 'px'; this.barElement.style.left = x + 'px'; - this.openDragBackdrop(this.barElement, this.ganttUpper.view.getDateByXPoint(x), this.item.end); - this.item.updateDate(this.ganttUpper.view.getDateByXPoint(x), this.item.end); + this.openDragBackdrop(this.barElement, start, this.item.end); + this.item.updateDate(start, this.item.end); } } else { const width = this.item.refs.width + event.distance.x; + const end = this.ganttUpper.view.getDateByXPoint(this.item.refs.x + width); if (width > dragMinWidth) { this.barElement.style.width = width + 'px'; - this.openDragBackdrop( - this.barElement, - this.item.start, - this.ganttUpper.view.getDateByXPoint(this.item.refs.x + width) - ); + this.openDragBackdrop(this.barElement, this.item.start, end); + this.item.updateDate(this.item.start, end); } - this.item.updateDate(this.item.start, this.ganttUpper.view.getDateByXPoint(this.item.refs.x + width)); } this.dragContainer.dragMoved.emit({ item: this.item.origin }); event.source.reset(); @@ -172,19 +171,12 @@ export class GanttBarDrag implements OnDestroy { dragRef.ended.subscribe((event) => { if (isBefore) { const width = this.item.refs.width + event.distance.x * -1; - if (width > dragMinWidth) { - this.item.updateDate(this.ganttUpper.view.getDateByXPoint(this.item.refs.x + event.distance.x), this.item.end); - } else { + if (width <= dragMinWidth) { this.item.updateDate(this.item.end.startOfDay(), this.item.end); } } else { const width = this.item.refs.width + event.distance.x; - if (width > dragMinWidth) { - this.item.updateDate( - this.item.start, - this.ganttUpper.view.getDateByXPoint(this.item.refs.x + this.item.refs.width + event.distance.x) - ); - } else { + if (width <= dragMinWidth) { this.item.updateDate(this.item.start, this.item.start.endOfDay()); } } diff --git a/packages/gantt/src/components/bar/bar.component.ts b/packages/gantt/src/components/bar/bar.component.ts index 61e97a17..df4ed087 100644 --- a/packages/gantt/src/components/bar/bar.component.ts +++ b/packages/gantt/src/components/bar/bar.component.ts @@ -14,8 +14,8 @@ import { QueryList, NgZone } from '@angular/core'; -import { fromEvent, merge, Observable } from 'rxjs'; -import { startWith, switchMap, takeUntil } from 'rxjs/operators'; +import { from, fromEvent, merge, Observable } from 'rxjs'; +import { startWith, switchMap, take, takeUntil } from 'rxjs/operators'; import { GanttBarDrag } from './bar-drag'; import { hexToRgb } from '../../utils/helpers'; import { GanttDragContainer } from '../../gantt-drag-container'; @@ -60,7 +60,17 @@ export class NgxGanttBarComponent extends GanttItemUpper implements OnInit, Afte } ngAfterViewInit() { - this.drag.createDrags(this.elementRef, this.item, this.ganttUpper); + // Note: the zone may be nooped through `BootstrapOptions` when bootstrapping the root module. This means + // the `onStable` will never emit any value. + const onStable$ = this.ngZone.isStable ? from(Promise.resolve()) : this.ngZone.onStable.pipe(take(1)); + // Normally this isn't in the zone, but it can cause performance regressions for apps + // using `zone-patch-rxjs` because it'll trigger a change detection when it unsubscribes. + this.ngZone.runOutsideAngular(() => { + onStable$.pipe(takeUntil(this.unsubscribe$)).subscribe(() => { + this.drag.createDrags(this.elementRef, this.item, this.ganttUpper); + }); + }); + this.setContentBackground(); this.handles.changes diff --git a/packages/gantt/src/gantt-dom.service.ts b/packages/gantt/src/gantt-dom.service.ts index 1247408b..31b46b98 100644 --- a/packages/gantt/src/gantt-dom.service.ts +++ b/packages/gantt/src/gantt-dom.service.ts @@ -30,6 +30,8 @@ export class GanttDomService implements OnDestroy { public mainContainer: Element; + public mainItems: Element; + public calendarOverlay: Element; public linksOverlay: Element; @@ -95,6 +97,7 @@ export class GanttDomService implements OnDestroy { this.container = this.root.getElementsByClassName('gantt-container')[0]; this.sideContainer = this.root.getElementsByClassName('gantt-side-container')[0]; this.mainContainer = this.root.getElementsByClassName('gantt-main-container')[0]; + this.mainItems = this.root.getElementsByClassName('gantt-main-items')[0]; this.calendarOverlay = this.root.getElementsByClassName('gantt-calendar-overlay')[0]; this.monitorScrollChange(); this.disableBrowserWheelEvent(); diff --git a/packages/gantt/src/views/view.ts b/packages/gantt/src/views/view.ts index 9eb0ddf7..aade6405 100644 --- a/packages/gantt/src/views/view.ts +++ b/packages/gantt/src/views/view.ts @@ -174,8 +174,8 @@ export abstract class GanttView { // 根据X坐标获取对应时间 getDateByXPoint(x: number) { - const indexOfSecondaryDate = Math.floor(x / this.getCellWidth()); - const matchDate = this.secondaryDatePoints[indexOfSecondaryDate]; + const indexOfSecondaryDate = Math.max(Math.floor(x / this.getCellWidth()), 0); + const matchDate = this.secondaryDatePoints[Math.min(this.secondaryDatePoints.length - 1, indexOfSecondaryDate)]; const dayWidth = this.getDayOccupancyWidth(matchDate?.start); if (dayWidth === this.getCellWidth()) { return matchDate?.start;