From 25b1b2d6202f52bde3748b1211d557e4c790b485 Mon Sep 17 00:00:00 2001 From: malangfox Date: Tue, 25 Jun 2024 17:46:14 +0900 Subject: [PATCH] feat: add dragThreshold option --- docs/src/pages/Options.mdx | 33 +++++++++++++++++++++++++++ src/Flicking.ts | 26 ++++++++++++++++++++-- src/control/AxesController.ts | 2 +- test/unit/Flicking.spec.ts | 42 +++++++++++++++++++++++++++++++++++ 4 files changed, 100 insertions(+), 3 deletions(-) diff --git a/docs/src/pages/Options.mdx b/docs/src/pages/Options.mdx index 4d65548db..939f01d68 100644 --- a/docs/src/pages/Options.mdx +++ b/docs/src/pages/Options.mdx @@ -857,6 +857,39 @@ It should be dragged above the threshold to change the current panel. +### dragThreshold +Minimal distance of user input before recognizing (unit: px). +It should be dragged above the dragThreshold to move the panel. + + + + + ```js + dragThreshold: 1 + ``` + + + + + { Panels(5) } + + + + + + + ```js + dragThreshold: 30 + ``` + + + + + { Panels(5) } + + + + ### interruptable Set animation to be interruptable by click/touch. diff --git a/src/Flicking.ts b/src/Flicking.ts index 22d6af9e3..73fca45df 100644 --- a/src/Flicking.ts +++ b/src/Flicking.ts @@ -73,6 +73,7 @@ export interface FlickingOptions { inputType: string[]; moveType: ValueOf | MoveTypeOptions>; threshold: number; + dragThreshold: number; interruptable: boolean; bounce: number | string | [number | string, number | string]; iOSEdgeSwipeThreshold: number; @@ -152,6 +153,7 @@ class Flicking extends Component { private _inputType: FlickingOptions["inputType"]; private _moveType: FlickingOptions["moveType"]; private _threshold: FlickingOptions["threshold"]; + private _dragThreshold: FlickingOptions["dragThreshold"]; private _interruptable: FlickingOptions["interruptable"]; private _bounce: FlickingOptions["bounce"]; private _iOSEdgeSwipeThreshold: FlickingOptions["iOSEdgeSwipeThreshold"]; @@ -350,7 +352,7 @@ class Flicking extends Component { public get align() { return this._align; } /** * Index of the panel to move when Flicking's {@link Flicking#init init()} is called. A zero-based integer - * @ko Flicking의 {@link Flicking#init init()}이 호출될 때 이동할 디폴트 패널의 인덱스로, 0부터 시작하는 정수입니다 + * @ko Flicking의 {@link Flicking#init init()}이 호출될 때 이동할 디폴트 패널의 인덱스로, 0부터 시작하는 정수입니다. * @type {number} * @default 0 * @see {@link https://naver.github.io/egjs-flicking/Options#defaultindex defaultIndex ( Options )} @@ -528,12 +530,20 @@ class Flicking extends Component { public get moveType() { return this._moveType; } /** * Movement threshold to change panel (unit: px). It should be dragged above the threshold to change the current panel. - * @ko 패널 변경을 위한 이동 임계값 (단위: px). 주어진 값 이상으로 스크롤해야만 패널 변경이 가능하다. + * @ko 패널 변경을 위한 이동 임계값 (단위: px). 주어진 값 이상으로 스크롤해야만 패널 변경이 가능합니다. * @type {number} * @default 40 * @see {@link https://naver.github.io/egjs-flicking/Options#threshold Threshold ( Options )} */ public get threshold() { return this._threshold; } + /** + * Minimal distance of user input before recognizing (unit: px). It should be dragged above the dragThreshold to move the panel. + * @ko 사용자의 입력을 인식하기 위한 최소한의 거리 (단위: px). 주어진 값 이상으로 스크롤해야만 패널이 움직입니다. + * @type {number} + * @default 1 + * @see {@link https://naver.github.io/egjs-flicking/Options#dragThreshold dragThreshold ( Options )} + */ + public get dragThreshold() { return this._dragThreshold; } /** * Set animation to be interruptable by click/touch. * @ko 사용자의 클릭/터치로 인해 애니메이션을 도중에 멈출 수 있도록 설정합니다. @@ -845,6 +855,16 @@ class Flicking extends Component { } public set threshold(val: FlickingOptions["threshold"]) { this._threshold = val; } + + public set dragThreshold(val: FlickingOptions["dragThreshold"]) { + this._dragThreshold = val; + const panInput = this._control.controller.panInput; + + if (panInput) { + panInput.options.threshold = val; + } + } + public set interruptable(val: FlickingOptions["interruptable"]) { this._interruptable = val; @@ -969,6 +989,7 @@ class Flicking extends Component { inputType = ["mouse", "touch"], moveType = "snap", threshold = 40, + dragThreshold = 1, interruptable = true, bounce = "20%", iOSEdgeSwipeThreshold = 30, @@ -1014,6 +1035,7 @@ class Flicking extends Component { this._inputType = inputType; this._moveType = moveType; this._threshold = threshold; + this._dragThreshold = dragThreshold; this._interruptable = interruptable; this._bounce = bounce; this._iOSEdgeSwipeThreshold = iOSEdgeSwipeThreshold; diff --git a/src/control/AxesController.ts b/src/control/AxesController.ts index a1d1f7ec7..59e0397ed 100644 --- a/src/control/AxesController.ts +++ b/src/control/AxesController.ts @@ -148,7 +148,7 @@ class AxesController { }); this._panInput = new PanInput(flicking.viewport.element, { inputType: flicking.inputType, - threshold: 1, + threshold: flicking.dragThreshold, iOSEdgeSwipeThreshold: flicking.iOSEdgeSwipeThreshold, preventDefaultOnDrag: flicking.preventDefaultOnDrag, scale: flicking.horizontal ? [flicking.camera.panelOrder === ORDER.RTL ? 1 : -1, 0] : [0, -1], diff --git a/test/unit/Flicking.spec.ts b/test/unit/Flicking.spec.ts index a5a3eb8fb..f961ac94d 100644 --- a/test/unit/Flicking.spec.ts +++ b/test/unit/Flicking.spec.ts @@ -689,6 +689,48 @@ describe("Flicking", () => { }); }); + describe("dragThreshold", () => { + it("is 1 by default", async () => { + const flicking = await createFlicking(El.DEFAULT_HORIZONTAL); + + expect(flicking.dragThreshold).to.equal(1); + }); + + it("should trigger move event when moving above dragThreshold", async () => { + const flicking = await createFlicking(El.DEFAULT_HORIZONTAL, { dragThreshold: 50 }); + const moveSpy = sinon.spy(); + flicking.on(EVENTS.MOVE, moveSpy); + + + await simulate(flicking.element, { deltaX: -51, duration: 3000 }); + + expect(moveSpy.called).to.be.true; + }); + + it("should not trigger move event when moving below dragThreshold", async () => { + const flicking = await createFlicking(El.DEFAULT_HORIZONTAL, { dragThreshold: 50 }); + const moveSpy = sinon.spy(); + flicking.on(EVENTS.MOVE, moveSpy); + + await simulate(flicking.element, { deltaX: -49, duration: 3000 }); + + expect(moveSpy.called).to.be.false; + }); + + it("should update axes option when changed", async () => { + const flicking = await createFlicking(El.DEFAULT_HORIZONTAL, { + dragThreshold: 50 + }); + const panOptions = flicking.control.controller.panInput.options; + const prevVal = panOptions.threshold; + + flicking.dragThreshold = 30; + + expect(prevVal).to.equal(50); + expect(panOptions.threshold).to.equal(30); + }); + }); + describe("interruptable", () => { it("is true by default", async () => { const flicking = await createFlicking(El.DEFAULT_HORIZONTAL);