Skip to content

Commit

Permalink
refactor(module:core): add drag service (#4350)
Browse files Browse the repository at this point in the history
* refactor(module:core): add nz drag service

* test: add drag service test

* test: cleanup test

* refactor: make drag service global instance

* fix: not necessary to remove handler

close #4340
  • Loading branch information
Wendell authored and hsuanxyz committed Nov 8, 2019
1 parent 1be6d51 commit 6a2c132
Show file tree
Hide file tree
Showing 8 changed files with 322 additions and 88 deletions.
90 changes: 36 additions & 54 deletions components/carousel/nz-carousel.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@

import { LEFT_ARROW, RIGHT_ARROW } from '@angular/cdk/keycodes';
import { Platform } from '@angular/cdk/platform';
import { DOCUMENT } from '@angular/common';
import {
AfterContentInit,
AfterViewInit,
Expand All @@ -35,12 +34,12 @@ import { Subject } from 'rxjs';
import { finalize, takeUntil } from 'rxjs/operators';

import {
isTouchEvent,
warnDeprecation,
InputBoolean,
InputNumber,
NzConfigService,
NzDomEventService,
NzDragService,
WithConfig
} from 'ng-zorro-antd/core';

Expand Down Expand Up @@ -143,24 +142,21 @@ export class NzCarouselComponent implements AfterContentInit, AfterViewInit, OnD
transitionInProgress: number | null;

private destroy$ = new Subject<void>();
private document: Document;
private gestureRect: ClientRect | null = null;
private pointerDelta: PointerVector | null = null;
private pointerPosition: PointerVector | null = null;
private isTransiting = false;
private isDragging = false;

constructor(
public nzConfigService: NzConfigService,
elementRef: ElementRef,
private renderer: Renderer2,
private cdr: ChangeDetectorRef,
private platform: Platform,
private nzDomEventService: NzDomEventService,
@Inject(DOCUMENT) document: any, // tslint:disable-line:no-any
public readonly nzConfigService: NzConfigService,
private readonly renderer: Renderer2,
private readonly cdr: ChangeDetectorRef,
private readonly platform: Platform,
private readonly nzDomEventService: NzDomEventService,
private readonly nzDragService: NzDragService,
@Optional() @Inject(NZ_CAROUSEL_CUSTOM_STRATEGIES) private customStrategies: NzCarouselStrategyRegistryItem[]
) {
this.document = document;
this.renderer.addClass(elementRef.nativeElement, 'ant-carousel');
this.el = elementRef.nativeElement;
}
Expand Down Expand Up @@ -229,7 +225,6 @@ export class NzCarouselComponent implements AfterContentInit, AfterViewInit, OnD
if (this.strategy) {
this.strategy.dispose();
}
this.dispose();

this.destroy$.next();
this.destroy$.complete();
Expand Down Expand Up @@ -317,46 +312,40 @@ export class NzCarouselComponent implements AfterContentInit, AfterViewInit, OnD
this.cdr.markForCheck();
}

/**
* Drag carousel.
* @param event
*/
pointerDown = (event: TouchEvent | MouseEvent) => {
if (!this.isDragging && !this.isTransiting && this.nzEnableSwipe) {
const point = isTouchEvent(event) ? event.touches[0] || event.changedTouches[0] : event;
this.isDragging = true;
this.clearScheduledTransition();
this.gestureRect = this.slickListEl.getBoundingClientRect();
this.pointerPosition = { x: point.clientX, y: point.clientY };

this.document.addEventListener('mousemove', this.pointerMove);
this.document.addEventListener('touchmove', this.pointerMove);
this.document.addEventListener('mouseup', this.pointerUp);
this.document.addEventListener('touchend', this.pointerUp);
}
};

pointerMove = (event: TouchEvent | MouseEvent) => {
if (this.isDragging) {
const point = isTouchEvent(event) ? event.touches[0] || event.changedTouches[0] : event;
this.pointerDelta = { x: point.clientX - this.pointerPosition!.x, y: point.clientY - this.pointerPosition!.y };
if (Math.abs(this.pointerDelta.x) > 5) {
this.strategy.dragging(this.pointerDelta);
}
}
};

pointerUp = () => {
if (this.isDragging && this.nzEnableSwipe) {
const delta = this.pointerDelta ? this.pointerDelta.x : 0;

// Switch to another slide if delta is third of the width.
if (Math.abs(delta) > this.gestureRect!.width / 3) {
this.goTo(delta > 0 ? this.activeIndex - 1 : this.activeIndex + 1);
} else {
this.goTo(this.activeIndex);
}

this.gestureRect = null;
this.pointerDelta = null;
this.isDragging = false;
this.dispose();
this.nzDragService.requestDraggingSequence(event).subscribe(
delta => {
this.pointerDelta = delta;
this.isDragging = true;
this.strategy.dragging(this.pointerDelta);
},
() => {},
() => {
if (this.nzEnableSwipe && this.isDragging) {
const xDelta = this.pointerDelta ? this.pointerDelta.x : 0;

// Switch to another slide if delta is bigger than third of the width.
if (Math.abs(xDelta) > this.gestureRect!.width / 3) {
this.goTo(xDelta > 0 ? this.activeIndex - 1 : this.activeIndex + 1);
} else {
this.goTo(this.activeIndex);
}

this.gestureRect = null;
this.pointerDelta = null;
}

this.isDragging = false;
}
);
}
};

Expand All @@ -365,11 +354,4 @@ export class NzCarouselComponent implements AfterContentInit, AfterViewInit, OnD
this.strategy.withCarouselContents(this.carouselContents);
}
}

private dispose(): void {
this.document.removeEventListener('mousemove', this.pointerMove);
this.document.removeEventListener('touchmove', this.pointerMove);
this.document.removeEventListener('touchend', this.pointerMove);
this.document.removeEventListener('mouseup', this.pointerMove);
}
}
68 changes: 34 additions & 34 deletions components/carousel/nz-carousel.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { Component, DebugElement, ViewChild } from '@angular/core';
import { fakeAsync, tick, ComponentFixture, TestBed } from '@angular/core/testing';
import { By } from '@angular/platform-browser';

import { dispatchKeyboardEvent } from 'ng-zorro-antd/core';
import { dispatchKeyboardEvent, dispatchMouseEvent } from 'ng-zorro-antd/core/testing';

import { NzCarouselContentDirective } from './nz-carousel-content.directive';
import { NZ_CAROUSEL_CUSTOM_STRATEGIES } from './nz-carousel-definitions';
Expand Down Expand Up @@ -240,6 +240,7 @@ describe('carousel', () => {
expect(resizeSpy).toHaveBeenCalledTimes(1);
}));

// TODO(wendzhue): no idea why this stops working with auditTime
it('should support swiping to switch', fakeAsync(() => {
swipe(testComponent.nzCarouselComponent, 500);
tickMilliseconds(fixture, 700);
Expand All @@ -255,88 +256,81 @@ describe('carousel', () => {
}));

it('should prevent swipes that are not long enough', fakeAsync(() => {
swipe(testComponent.nzCarouselComponent, 2);
swipe(testComponent.nzCarouselComponent, 57);
tickMilliseconds(fixture, 700);
expect(carouselContents[0].nativeElement.classList).toContain('slick-active');
}));

it('should disable dragging during transitioning', fakeAsync(() => {
tickMilliseconds(fixture, 700);
testComponent.nzCarouselComponent.goTo(1);
swipe(testComponent.nzCarouselComponent, 500);
tickMilliseconds(fixture, 700);
expect(carouselContents[1].nativeElement.classList).toContain('slick-active');
}));
});

describe('strategies', () => {
let fixture: ComponentFixture<NzTestCarouselBasicComponent>;
let testComponent: NzTestCarouselBasicComponent;
let carouselContents: DebugElement[];

beforeEach(() => {
fixture = TestBed.createComponent(NzTestCarouselBasicComponent);
fixture.detectChanges();
testComponent = fixture.debugElement.componentInstance;
carouselContents = fixture.debugElement.queryAll(By.directive(NzCarouselContentDirective));
});

describe('transform strategy', () => {
it('should set transform', fakeAsync(() => {
it('horizontal transform', fakeAsync(() => {
expect(testComponent.nzCarouselComponent.slickTrackEl.style.transform).toBe(`translate3d(0px, 0px, 0px)`);

swipe(testComponent.nzCarouselComponent, 500);
testComponent.nzCarouselComponent.next();
tickMilliseconds(fixture, 700);
expect(testComponent.nzCarouselComponent.slickTrackEl.style.transform).not.toBe(`translate3d(0px, 0px, 0px)`);

testComponent.nzCarouselComponent.pre();
tickMilliseconds(fixture, 700);

swipe(testComponent.nzCarouselComponent, -500);
expect(testComponent.nzCarouselComponent.slickTrackEl.style.transform).toBe(`translate3d(0px, 0px, 0px)`);
tickMilliseconds(fixture, 700);

// From first to last.
swipe(testComponent.nzCarouselComponent, -500);
expect(testComponent.nzCarouselComponent.slickTrackEl.style.transform).not.toBe(`translate3d(0px, 0px, 0px)`);
testComponent.nzCarouselComponent.pre();
tickMilliseconds(fixture, 700);
expect(testComponent.nzCarouselComponent.slickTrackEl.style.transform).not.toBe(`translate3d(0px, 0px, 0px)`);

// From last to first.
swipe(testComponent.nzCarouselComponent, 500);
expect(testComponent.nzCarouselComponent.slickTrackEl.style.transform).not.toBe(`translate3d(0px, 0px, 0px)`);
testComponent.nzCarouselComponent.next();
tickMilliseconds(fixture, 700);
expect(testComponent.nzCarouselComponent.slickTrackEl.style.transform).toBe(`translate3d(0px, 0px, 0px)`);
}));

it('vertical', fakeAsync(() => {
it('vertical transform', fakeAsync(() => {
testComponent.vertical = true;
fixture.detectChanges();

expect(testComponent.nzCarouselComponent.slickTrackEl.style.transform).toBe(`translate3d(0px, 0px, 0px)`);

swipe(testComponent.nzCarouselComponent, 500);
expect(testComponent.nzCarouselComponent.el.style.transform).not.toBe(`translate3d(0px, 0px, 0px)`);
testComponent.nzCarouselComponent.next();
tickMilliseconds(fixture, 700);
expect(testComponent.nzCarouselComponent.el.style.transform).not.toBe(`translate3d(0px, 0px, 0px)`);

swipe(testComponent.nzCarouselComponent, -500);
expect(testComponent.nzCarouselComponent.slickTrackEl.style.transform).toBe(`translate3d(0px, 0px, 0px)`);
testComponent.nzCarouselComponent.pre();
tickMilliseconds(fixture, 700);
expect(testComponent.nzCarouselComponent.slickTrackEl.style.transform).toBe(`translate3d(0px, 0px, 0px)`);

// From first to last.
swipe(testComponent.nzCarouselComponent, -500);
expect(testComponent.nzCarouselComponent.slickTrackEl.style.transform).not.toBe(`translate3d(0px, 0px, 0px)`);
testComponent.nzCarouselComponent.pre();
tickMilliseconds(fixture, 700);
expect(testComponent.nzCarouselComponent.slickTrackEl.style.transform).not.toBe(`translate3d(0px, 0px, 0px)`);

// From last to first.
swipe(testComponent.nzCarouselComponent, 500);
expect(testComponent.nzCarouselComponent.slickTrackEl.style.transform).not.toBe(`translate3d(0px, 0px, 0px)`);
testComponent.nzCarouselComponent.next();
tickMilliseconds(fixture, 700);
expect(testComponent.nzCarouselComponent.slickTrackEl.style.transform).toBe(`translate3d(0px, 0px, 0px)`);
}));

it('should disable dragging during transitioning', fakeAsync(() => {
tickMilliseconds(fixture, 700);
testComponent.nzCarouselComponent.goTo(1);
swipe(testComponent.nzCarouselComponent, 500);
tickMilliseconds(fixture, 700);
expect(carouselContents[1].nativeElement.classList).toContain('slick-active');
}));
});

// Already covered in components specs.
describe('opacity strategy', () => {});
// describe('opacity strategy', () => {});
});
});

Expand Down Expand Up @@ -394,7 +388,13 @@ function tickMilliseconds<T>(fixture: ComponentFixture<T>, seconds: number = 1):
* @param Distance: Positive to right. Negative to left.
*/
function swipe(carousel: NzCarouselComponent, distance: number): void {
carousel.pointerDown(new MouseEvent('mousedown', { clientX: 500, clientY: 0 }));
carousel.pointerMove(new MouseEvent('mousemove', { clientX: 500 - distance, clientY: 0 }));
carousel.pointerUp();
carousel.pointerDown(
new MouseEvent('mousedown', {
clientX: 500,
clientY: 0
})
);

dispatchMouseEvent(document, 'mousemove', 500 - distance, 0);
dispatchMouseEvent(document, 'mouseup');
}
9 changes: 9 additions & 0 deletions components/core/services/drag/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
/**
* @license
* Copyright Alibaba.com All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE
*/

export * from './public-api';
Loading

0 comments on commit 6a2c132

Please sign in to comment.