-
Notifications
You must be signed in to change notification settings - Fork 127
/
Flicking.ts
1775 lines (1618 loc) · 71.2 KB
/
Flicking.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/*
* Copyright (c) 2015 NAVER Corp.
* egjs projects are licensed under the MIT license
*/
import Component, { ComponentEvent } from "@egjs/component";
import FlickingError from "./core/FlickingError";
import Viewport from "./core/Viewport";
import AutoResizer from "./core/AutoResizer";
import { Panel } from "./core/panel";
import { VanillaElementProvider } from "./core/panel/provider";
import VirtualManager, { VirtualOptions } from "./core/VirtualManager";
import { Control, SnapControl, SnapControlOptions, FreeControl, StrictControl, FreeControlOptions, StrictControlOptions } from "./control";
import { Camera } from "./camera";
import { Renderer, VanillaRenderer, ExternalRenderer, RendererOptions, NormalRenderingStrategy, VirtualRenderingStrategy } from "./renderer";
import { EVENTS, ALIGN, MOVE_TYPE, DIRECTION, CIRCULAR_FALLBACK } from "./const/external";
import * as ERROR from "./const/error";
import { findIndex, getElement, includes, parseElement } from "./utils";
import { HoldStartEvent, HoldEndEvent, MoveStartEvent, SelectEvent, MoveEvent, MoveEndEvent, WillChangeEvent, WillRestoreEvent, NeedPanelEvent, VisibleChangeEvent, ReachEdgeEvent, ReadyEvent, AfterResizeEvent, BeforeResizeEvent, ChangedEvent, RestoredEvent, PanelChangeEvent } from "./type/event";
import { LiteralUnion, ValueOf } from "./type/internal";
import { ElementLike, Plugin, Status, MoveTypeOptions } from "./type/external";
/**
* @interface
*/
export interface FlickingEvents {
[EVENTS.READY]: ReadyEvent;
[EVENTS.BEFORE_RESIZE]: BeforeResizeEvent;
[EVENTS.AFTER_RESIZE]: AfterResizeEvent;
[EVENTS.HOLD_START]: HoldStartEvent;
[EVENTS.HOLD_END]: HoldEndEvent;
[EVENTS.MOVE_START]: MoveStartEvent;
[EVENTS.MOVE]: MoveEvent;
[EVENTS.MOVE_END]: MoveEndEvent;
[EVENTS.WILL_CHANGE]: WillChangeEvent;
[EVENTS.CHANGED]: ChangedEvent;
[EVENTS.WILL_RESTORE]: WillRestoreEvent;
[EVENTS.RESTORED]: RestoredEvent;
[EVENTS.SELECT]: SelectEvent;
[EVENTS.NEED_PANEL]: NeedPanelEvent;
[EVENTS.VISIBLE_CHANGE]: VisibleChangeEvent;
[EVENTS.REACH_EDGE]: ReachEdgeEvent;
[EVENTS.PANEL_CHANGE]: PanelChangeEvent;
}
/**
* @interface
*/
export interface FlickingOptions {
// UI / LAYOUT
align: LiteralUnion<ValueOf<typeof ALIGN>> | number | { panel: number | string; camera: number | string };
defaultIndex: number;
horizontal: boolean;
circular: boolean;
circularFallback: LiteralUnion<ValueOf<typeof CIRCULAR_FALLBACK>>;
bound: boolean;
adaptive: boolean;
panelsPerView: number;
noPanelStyleOverride: boolean;
resizeOnContentsReady: boolean;
nested: boolean;
// EVENT
needPanelThreshold: number;
preventEventsBeforeInit: boolean;
// ANIMATION
deceleration: number;
duration: number;
easing: (x: number) => number;
// INPUT
inputType: string[];
moveType: ValueOf<typeof MOVE_TYPE> | MoveTypeOptions<ValueOf<typeof MOVE_TYPE>>;
threshold: number;
interruptable: boolean;
bounce: number | string | [number | string, number | string];
iOSEdgeSwipeThreshold: number;
preventClickOnDrag: boolean;
preventDefaultOnDrag: boolean;
disableOnInit: boolean;
changeOnHold: boolean;
// PERFORMANCE
renderOnlyVisible: boolean;
virtual: VirtualOptions | null;
// OTHERS
autoInit: boolean;
autoResize: boolean;
useResizeObserver: boolean;
resizeDebounce: number;
maxResizeDebounce: number;
useFractionalSize: boolean;
externalRenderer: ExternalRenderer | null;
// @deprecated
renderExternal: {
renderer: new (options: RendererOptions) => ExternalRenderer;
rendererOptions: RendererOptions;
} | null;
}
/**
* @extends Component
* @support {"ie": "9+(with polyfill)", "ch" : "latest", "ff" : "latest", "sf" : "latest", "edge" : "latest", "ios" : "7+", "an" : "4.X+"}
* @requires {@link https://github.com/naver/egjs-component|@egjs/component}
* @requires {@link https://github.com/naver/egjs-axes|@egjs/axes}
*/
class Flicking extends Component<FlickingEvents> {
/**
* Version info string
* @ko 버전정보 문자열
* @type {string}
* @readonly
* @example
* ```ts
* Flicking.VERSION; // ex) 4.0.0
* ```
*/
public static VERSION = "#__VERSION__#";
// Core components
private _viewport: Viewport;
private _autoResizer: AutoResizer;
private _camera: Camera;
private _control: Control;
private _renderer: Renderer;
private _virtualManager: VirtualManager;
// Options
private _align: FlickingOptions["align"];
private _defaultIndex: FlickingOptions["defaultIndex"];
private _horizontal: FlickingOptions["horizontal"];
private _circular: FlickingOptions["circular"];
private _circularFallback: FlickingOptions["circularFallback"];
private _bound: FlickingOptions["bound"];
private _adaptive: FlickingOptions["adaptive"];
private _panelsPerView: FlickingOptions["panelsPerView"];
private _noPanelStyleOverride: FlickingOptions["noPanelStyleOverride"];
private _resizeOnContentsReady: FlickingOptions["resizeOnContentsReady"];
private _virtual: FlickingOptions["virtual"];
private _nested: FlickingOptions["nested"];
private _needPanelThreshold: FlickingOptions["needPanelThreshold"];
private _preventEventsBeforeInit: FlickingOptions["preventEventsBeforeInit"];
private _deceleration: FlickingOptions["deceleration"];
private _duration: FlickingOptions["duration"];
private _easing: FlickingOptions["easing"];
private _inputType: FlickingOptions["inputType"];
private _moveType: FlickingOptions["moveType"];
private _threshold: FlickingOptions["threshold"];
private _interruptable: FlickingOptions["interruptable"];
private _bounce: FlickingOptions["bounce"];
private _iOSEdgeSwipeThreshold: FlickingOptions["iOSEdgeSwipeThreshold"];
private _preventClickOnDrag: FlickingOptions["preventClickOnDrag"];
private _preventDefaultOnDrag: FlickingOptions["preventDefaultOnDrag"];
private _disableOnInit: FlickingOptions["disableOnInit"];
private _changeOnHold: FlickingOptions["changeOnHold"];
private _renderOnlyVisible: FlickingOptions["renderOnlyVisible"];
private _autoInit: FlickingOptions["autoInit"];
private _autoResize: FlickingOptions["autoResize"];
private _useResizeObserver: FlickingOptions["useResizeObserver"];
private _resizeDebounce: FlickingOptions["resizeDebounce"];
private _maxResizeDebounce: FlickingOptions["maxResizeDebounce"];
private _useFractionalSize: FlickingOptions["useFractionalSize"];
private _externalRenderer: FlickingOptions["externalRenderer"];
private _renderExternal: FlickingOptions["renderExternal"];
// Internal State
private _initialized: boolean;
private _plugins: Plugin[];
// Components
/**
* {@link Control} instance of the Flicking
* @ko 현재 Flicking에 활성화된 {@link Control} 인스턴스
* @type {Control}
* @default SnapControl
* @readonly
* @see Control
* @see SnapControl
* @see FreeControl
*/
public get control() { return this._control; }
/**
* {@link Camera} instance of the Flicking
* @ko 현재 Flicking에 활성화된 {@link Camera} 인스턴스
* @type {Camera}
* @default LinearCamera
* @readonly
* @see Camera
* @see LinearCamera
* @see BoundCamera
* @see CircularCamera
*/
public get camera() { return this._camera; }
/**
* {@link Renderer} instance of the Flicking
* @ko 현재 Flicking에 활성화된 {@link Renderer} 인스턴스
* @type {Renderer}
* @default VanillaRenderer
* @readonly
* @see Renderer
* @see VanillaRenderer
* @see ExternalRenderer
*/
public get renderer() { return this._renderer; }
/**
* A component that manages viewport size
* @ko 뷰포트 크기 정보를 담당하는 컴포넌트
* @type {Viewport}
* @readonly
* @see Viewport
*/
public get viewport() { return this._viewport; }
// Internal States
/**
* Whether Flicking's {@link Flicking#init init()} is called.
* This is `true` when {@link Flicking#init init()} is called, and is `false` after calling {@link Flicking#destroy destroy()}.
* @ko Flicking의 {@link Flicking#init init()}이 호출되었는지를 나타내는 멤버 변수.
* 이 값은 {@link Flicking#init init()}이 호출되었으면 `true`로 변하고, {@link Flicking#destroy destroy()}호출 이후에 다시 `false`로 변경됩니다.
* @type {boolean}
* @default false
* @readonly
*/
public get initialized() { return this._initialized; }
/**
* Whether the `circular` option is enabled.
* The {@link Flicking#circular circular} option can't be enabled when sum of the panel sizes are too small.
* @ko {@link Flicking#circular circular} 옵션이 활성화되었는지 여부를 나타내는 멤버 변수.
* {@link Flicking#circular circular} 옵션은 패널의 크기의 합이 충분하지 않을 경우 비활성화됩니다.
* @type {boolean}
* @default false
* @readonly
*/
public get circularEnabled() { return this._camera.circularEnabled; }
/**
* Whether the `virtual` option is enabled.
* The {@link Flicking#virtual virtual} option can't be enabled when {@link Flicking#panelsPerView panelsPerView} is less or equal than zero.
* @ko {@link Flicking#virtual virtual} 옵션이 활성화되었는지 여부를 나타내는 멤버 변수.
* {@link Flicking#virtual virtual} 옵션은 {@link Flicking#panelsPerView panelsPerView} 옵션의 값이 0보다 같거나 작으면 비활성화됩니다.
* @type {boolean}
* @default false
* @readonly
*/
public get virtualEnabled() { return this._panelsPerView > 0 && this._virtual != null; }
/**
* Index number of the {@link Flicking#currentPanel currentPanel}
* @ko {@link Flicking#currentPanel currentPanel}의 인덱스 번호
* @type {number}
* @default 0
* @readonly
*/
public get index() { return this._control.activeIndex; }
/**
* The root(`.flicking-viewport`) element
* @ko root(`.flicking-viewport`) 엘리먼트
* @type {HTMLElement}
* @readonly
*/
public get element() { return this._viewport.element; }
/**
* Currently active panel
* @ko 현재 선택된 패널
* @type {Panel}
* @readonly
* @see Panel
*/
public get currentPanel() { return this._control.activePanel; }
/**
* Array of panels
* @ko 전체 패널들의 배열
* @type {Panel[]}
* @readonly
* @see Panel
*/
public get panels() { return this._renderer.panels; }
/**
* Count of panels
* @ko 전체 패널의 개수
* @type {number}
* @readonly
*/
public get panelCount() { return this._renderer.panelCount; }
/**
* Array of panels that is visible at the current position
* @ko 현재 보이는 패널의 배열
* @type {Panel[]}
* @readonly
* @see Panel
*/
public get visiblePanels() { return this._camera.visiblePanels; }
/**
* Whether Flicking's animating
* @ko 현재 애니메이션 동작 여부
* @type {boolean}
* @readonly
*/
public get animating() { return this._control.animating; }
/**
* Whether user is clicking or touching
* @ko 현재 사용자가 클릭/터치중인지 여부
* @type {boolean}
* @readonly
*/
public get holding() { return this._control.holding; }
/**
* A current list of activated plugins
* @ko 현재 활성화된 플러그인 목록
* @type {Plugin[]}
* @readonly
*/
public get activePlugins() { return this._plugins; }
// Options Getter
// UI / LAYOUT
/**
* Align position of the panels within viewport. You can set different values each for the panel and camera
* @ko 뷰포트 내에서 패널 정렬방식을 설정하는 옵션. 카메라와 패널 개별로 옵션을 설정할 수도 있습니다
* @type {ALIGN | string | number | { panel: string | number, camera: string | number }}
* @property {ALIGN | string | number} panel The align value for each {@link Panel}s<ko>개개의 {@link Panel}에 적용할 값</ko>
* @property {ALIGN | string | number} camera The align value for {@link Camera}<ko>{@link Camera}에 적용할 값</ko>
* @default "center"
* @see {@link https://naver.github.io/egjs-flicking/Options#align align ( Options )}
* @example
* ```ts
* const possibleOptions = [
* // Literal strings
* "prev", "center", "next",
* // % values, applied to both panel & camera
* "0%", "25%", "42%",
* // px values, arithmetic calculation with (+/-) is also allowed.
* "0px", "100px", "50% - 25px",
* // numbers, same to number + px ("0px", "100px")
* 0, 100, 1000,
* // Setting a different value for panel & camera
* { panel: "10%", camera: "25%" }
* ];
*
* possibleOptions.forEach(align => {
* new Flicking("#el", { align });
* });
* ```
*/
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부터 시작하는 정수입니다
* @type {number}
* @default 0
* @see {@link https://naver.github.io/egjs-flicking/Options#defaultindex defaultIndex ( Options )}
*/
public get defaultIndex() { return this._defaultIndex; }
/**
* Direction of panel movement (true: horizontal, false: vertical)
* @ko 패널 이동 방향 (true: 가로방향, false: 세로방향)
* @type {boolean}
* @default true
* @see {@link https://naver.github.io/egjs-flicking/Options#horizontal horizontal ( Options )}
*/
public get horizontal() { return this._horizontal; }
/**
* Enables circular(continuous loop) mode, which connects first/last panel for continuous scrolling.
* @ko 순환 모드를 활성화합니다. 순환 모드에서는 양 끝의 패널이 서로 연결되어 끊김없는 스크롤이 가능합니다.
* @type {boolean}
* @default false
* @see {@link https://naver.github.io/egjs-flicking/Options#circular circular ( Options )}
*/
public get circular() { return this._circular; }
/**
* Set panel control mode for the case when circular cannot be enabled.
* "linear" will set the view's range from the top of the first panel to the top of the last panel.
* "bound" will prevent the view from going out of the first/last panel, so it won't show empty spaces before/after the first/last panel.
* @ko 순환 모드 사용 불가능시 사용할 패널 조작 범위 설정 방식을 변경합니다.
* "linear" 사용시 시점이 첫번째 엘리먼트 위에서부터 마지막 엘리먼트 위까지 움직일 수 있도록 설정합니다.
* "bound" 사용시 시점이 첫번째 엘리먼트와 마지막 엘리먼트의 끝과 끝 사이에서 움직일 수 있도록 설정합니다.
* @see CIRCULAR_FALLBACK
* @type {string}
* @default "linear"
* @see {@link https://naver.github.io/egjs-flicking/Options#circularfallback circularFallback ( Options )}
*/
public get circularFallback() { return this._circularFallback; }
/**
* Prevent the view(camera element) from going out of the first/last panel, so it won't show empty spaces before/after the first/last panel
* Only can be enabled when `circular=false`
* @ko 뷰(카메라 엘리먼트)가 첫번째와 마지막 패널 밖으로 넘어가지 못하게 하여, 첫번째/마지막 패널 전/후의 빈 공간을 보이지 않도록 하는 옵션입니다
* `circular=false`인 경우에만 사용할 수 있습니다
* @type {boolean}
* @default false
* @see {@link https://naver.github.io/egjs-flicking/Options#bound bound ( Options )}
*/
public get bound() { return this._bound; }
/**
* Update height of the viewport element after movement same to the height of the panel below. This can be only enabled when `horizontal=true`
* @ko 이동한 후 뷰포트 엘리먼트의 크기를 현재 패널의 높이와 동일하게 설정합니다. `horizontal=true`인 경우에만 사용할 수 있습니다.
* @type {boolean}
* @default false
* @see {@link https://naver.github.io/egjs-flicking/Options#adaptive adaptive ( Options )}
*/
public get adaptive() { return this._adaptive; }
/**
* A visible number of panels on viewport. Enabling this option will automatically resize panel size
* @ko 한 화면에 보이는 패널의 개수. 이 옵션을 활성화할 경우 패널의 크기를 강제로 재조정합니다
* @type {number}
* @default -1
* @see {@link https://naver.github.io/egjs-flicking/Options#panelsperview panelsPerView ( Options )}
*/
public get panelsPerView() { return this._panelsPerView; }
/**
* Enabling this option will not change `width/height` style of the panels if {@link Flicking#panelsPerView} is enabled.
* This behavior can be useful in terms of performance when you're manually managing all panel sizes
* @ko 이 옵션을 활성화할 경우, {@link Flicking#panelsPerView} 옵션이 활성화되었을 때 패널의 `width/height` 스타일을 변경하지 않도록 설정합니다.
* 모든 패널들의 크기를 직접 관리하고 있을 경우, 이 옵션을 활성화하면 성능면에서 유리할 수 있습니다
* @type {boolean}
* @default false
*/
public get noPanelStyleOverride() { return this._noPanelStyleOverride; }
/**
* Enabling this option will automatically call {@link Flicking#resize} when all image/video inside panels are loaded.
* This can be useful when you have contents inside Flicking that changes its size when it's loaded
* @ko 이 옵션을 활성화할 경우, Flicking 패널 내부의 이미지/비디오들이 로드되었을 때 자동으로 {@link Flicking#resize}를 호출합니다.
* 이 동작은 Flicking 내부에 로드 전/후로 크기가 변하는 콘텐츠를 포함하고 있을 때 유용하게 사용하실 수 있습니다.
* @type {boolean}
* @default false
* @see {@link https://naver.github.io/egjs-flicking/Options#resizeOnContentsReady resizeOnContentsReady ( Options )}
*/
public get resizeOnContentsReady() { return this._resizeOnContentsReady; }
/**
* If you enable this option on child Flicking when the Flicking is placed inside the Flicking, the parent Flicking will move in the same direction after the child Flicking reaches the first/last panel.
* If the parent Flicking and child Flicking have different horizontal option, you do not need to set this option.
* @ko Flicking 내부에 Flicking이 배치될 때 하위 Flicking에서 이 옵션을 활성화하면 하위 Flicking이 첫/마지막 패널에 도달한 뒤부터 같은 방향으로 상위 Flicking이 움직입니다.
* 만약 상위 Flicking과 하위 Flicking이 서로 다른 horizontal 옵션을 가지고 있다면 이 옵션을 설정할 필요가 없습니다.
* @type {boolean}
* @default false
* @see {@link https://naver.github.io/egjs-flicking/Options#nested nested ( Options )}
*/
public get nested() { return this._nested; }
// EVENTS
/**
* A Threshold from viewport edge before triggering `needPanel` event
* @ko `needPanel`이벤트가 발생하기 위한 뷰포트 끝으로부터의 최대 거리
* @type {number}
* @default 0
* @see {@link https://naver.github.io/egjs-flicking/Options#needpanelthreshold needPanelThreshold ( Options )}
*/
public get needPanelThreshold() { return this._needPanelThreshold; }
/**
* When enabled, events are not triggered before `ready` when initializing
* @ko 활성화할 경우 초기화시 `ready` 이벤트 이전의 이벤트가 발생하지 않습니다.
* @type {boolean}
* @default true
* @see {@link https://naver.github.io/egjs-flicking/Options#preventeventsbeforeinit preventEventsBeforeInit ( Options )}
*/
public get preventEventsBeforeInit() { return this._preventEventsBeforeInit; }
// ANIMATION
/**
* Deceleration value for panel movement animation which is triggered by user input. A higher value means a shorter animation time
* @ko 사용자의 동작으로 가속도가 적용된 패널 이동 애니메이션의 감속도. 값이 높을수록 애니메이션 실행 시간이 짧아집니다
* @type {number}
* @default 0.0075
* @see {@link https://naver.github.io/egjs-flicking/Options#deceleration deceleration ( Options )}
*/
public get deceleration() { return this._deceleration; }
/**
* An easing function applied to the panel movement animation. Default value is `easeOutCubic`
* @ko 패널 이동 애니메이션에 적용할 easing 함수. 기본값은 `easeOutCubic`이다
* @type {function}
* @default x => 1 - Math.pow(1 - x, 3)
* @see Easing Functions Cheat Sheet {@link http://easings.net/} <ko>이징 함수 Cheat Sheet {@link http://easings.net/}</ko>
* @see {@link https://naver.github.io/egjs-flicking/Options#easing Easing ( Options )}
*/
public get easing() { return this._easing; }
/**
* Default duration of the animation (ms)
* @ko 디폴트 애니메이션 재생 시간 (ms)
* @type {number}
* @default 500
* @see {@link https://naver.github.io/egjs-flicking/Options#duration duration ( Options )}
*/
public get duration() { return this._duration; }
// INPUT
/**
* Types of input devices to enable
* @ko 활성화할 입력 장치 종류
* @type {string[]}
* @default ["touch", "mouse"]
* @see {@link https://naver.github.io/egjs-axes/Options#paninput-options Possible values (PanInputOption#inputType)}
* <ko>{@link https://naver.github.io/egjs-axes/Options#paninput-options 가능한 값들 (PanInputOption#inputType)}</ko>
* @see {@link https://naver.github.io/egjs-flicking/Options#inputtype inputType ( Options )}
*/
public get inputType() { return this._inputType; }
/**
* Movement style by user input. This will change instance type of {@link Flicking#control}
* You can use the values of the constant {@link MOVE_TYPE}
* @ko 사용자 입력에 의한 이동 방식. 이 값에 따라 {@link Flicking#control}의 인스턴스 타입이 결정됩니다
* 상수 {@link MOVE_TYPE}에 정의된 값들을 이용할 수 있습니다
* @type {MOVE_TYPE | Pair<string, object>}
* @default "snap"
* @see {@link https://naver.github.io/egjs-flicking/Options#movetype moveType ( Options )}
* @example
* |moveType|control|options|
* |:---:|:---:|:---:|
* |"snap"|{@link SnapControl}||
* |"freeScroll"|{@link FreeControl}|{@link FreeControlOptions}|
*
* ```ts
* import Flicking, { MOVE_TYPE } from "@egjs/flicking";
*
* const flicking = new Flicking({
* moveType: MOVE_TYPE.SNAP
* });
* ```
*
* ```ts
* const flicking = new Flicking({
* // If you want more specific settings for the moveType
* // [moveType, options for that moveType]
* // In this case, it's ["freeScroll", FreeControlOptions]
* moveType: [MOVE_TYPE.FREE_SCROLL, { stopAtEdge: true }]
* });
* ```
*/
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). 주어진 값 이상으로 스크롤해야만 패널 변경이 가능하다.
* @type {number}
* @default 40
* @see {@link https://naver.github.io/egjs-flicking/Options#threshold Threshold ( Options )}
*/
public get threshold() { return this._threshold; }
/**
* Set animation to be interruptable by click/touch.
* @ko 사용자의 클릭/터치로 인해 애니메이션을 도중에 멈출 수 있도록 설정합니다.
* @type {boolean}
* @default true
* @see {@link https://naver.github.io/egjs-flicking/Options#interruptable Interruptable ( Options )}
*/
public get interruptable() { return this._interruptable; }
/**
* The size value of the bounce area. Only can be enabled when `circular=false`.
* You can set different bounce value for prev/next direction by using array.
* `number` for px value, and `string` for px, and % value relative to viewport size.
* You have to call {@link Control#updateInput} after changing this to take effect.
* @ko Flicking이 최대 영역을 넘어서 갈 수 있는 최대 크기. `circular=false`인 경우에만 사용할 수 있습니다.
* 배열을 통해 prev/next 방향에 대해 서로 다른 바운스 값을 지정할 수 있습니다.
* `number`를 통해 px값을, `stirng`을 통해 px 혹은 뷰포트 크기 대비 %값을 사용할 수 있습니다.
* 이 값을 변경시 {@link Control#updateInput}를 호출해야 합니다.
* @type {string | number | Array<string | number>}
* @default "20%"
* @see {@link https://naver.github.io/egjs-flicking/Options#bounce bounce ( Options )}
* @example
* ```ts
* const possibleOptions = [
* // % values, relative to viewport element(".flicking-viewport")'s size
* "0%", "25%", "42%",
* // px values, arithmetic calculation with (+/-) is also allowed.
* "0px", "100px", "50% - 25px",
* // numbers, same to number + px ("0px", "100px")
* 0, 100, 1000
* ];
* ```
*
* @example
* ```ts
* const flicking = new Flicking("#el", { bounce: "20%" });
*
* flicking.bounce = "100%";
* flicking.control.updateInput(); // Call this to update!
* ```
*/
public get bounce() { return this._bounce; }
/**
* Size of the area from the right edge in iOS safari (in px) which enables swipe-back or swipe-forward
* @ko iOS Safari에서 swipe를 통한 뒤로가기/앞으로가기를 활성화하는 오른쪽 끝으로부터의 영역의 크기 (px)
* @type {number}
* @default 30
* @see {@link https://naver.github.io/egjs-flicking/Options#iosedgeswipethreshold iOSEdgeSwipeThreshold ( Options )}
*/
public get iOSEdgeSwipeThreshold() { return this._iOSEdgeSwipeThreshold; }
/**
* Automatically prevent `click` event if the user has dragged at least a single pixel on the viewport element
* @ko 사용자가 뷰포트 영역을 1픽셀이라도 드래그했을 경우 자동으로 {@link https://developer.mozilla.org/ko/docs/Web/API/Element/click_event click} 이벤트를 취소합니다
* @type {boolean}
* @default true
* @see {@link https://naver.github.io/egjs-flicking/Options#preventclickondrag preventClickOnDrag ( Options )}
*/
public get preventClickOnDrag() { return this._preventClickOnDrag; }
/**
* Whether to use the {@link https://developer.mozilla.org/ko/docs/Web/API/Event/preventDefault preventDefault} when the user starts dragging
* @ko 사용자가 드래그를 시작할 때 {@link https://developer.mozilla.org/ko/docs/Web/API/Event/preventDefault preventDefault} 실행 여부
* @type {boolean}
* @default false
* @see {@link https://naver.github.io/egjs-flicking/Options#preventDefaultOnDrag preventDefaultOnDrag ( Options )}
*/
public get preventDefaultOnDrag() { return this._preventDefaultOnDrag; }
/**
* Automatically call {@link Flicking#disableInput disableInput()} on initialization
* @ko Flicking init시에 {@link Flicking#disableInput disableInput()}을 바로 호출합니다
* @type {boolean}
* @default false
* @see {@link https://naver.github.io/egjs-flicking/Options#disableoninit disableOnInit ( Options )}
*/
public get disableOnInit() { return this._disableOnInit; }
/**
* Change active panel index on mouse/touch hold while animating.
* `index` of the `willChange`/`willRestore` event will be used as new index.
* @ko 애니메이션 도중 마우스/터치 입력시 현재 활성화된 패널의 인덱스를 변경합니다.
* `willChange`/`willRestore` 이벤트의 `index`값이 새로운 인덱스로 사용될 것입니다.
* @type {boolean}
* @default false
* @see {@link https://naver.github.io/egjs-flicking/Options#changeonhold changeOnHold ( Options )}
*/
public get changeOnHold() { return this._changeOnHold; }
// PERFORMANCE
/**
* Whether to render visible panels only. This can dramatically increase performance when there're many panels
* @ko 보이는 패널만 렌더링할지 여부를 설정합니다. 패널이 많을 경우에 퍼포먼스를 크게 향상시킬 수 있습니다
* @type {boolean}
* @default false
* @see {@link https://naver.github.io/egjs-flicking/Options#renderonlyvisible renderOnlyVisible ( Options )}
*/
public get renderOnlyVisible() { return this._renderOnlyVisible; }
/**
* By enabling this option, it will reduce memory consumption by restricting the number of DOM elements to `panelsPerView + 1`
* Must be used with `panelsPerview`.
* After Flicking's initialized, this property can be used to add/remove the panel count.
* @ko 이 옵션을 활성화할 경우 패널 엘리먼트의 개수를 `panelsPerView + 1` 개로 고정함으로써, 메모리 사용량을 줄일 수 있습니다.
* `panelsPerView` 옵션과 함께 사용되어야만 합니다.
* Flicking 초기화 이후에, 이 프로퍼티는 렌더링하는 패널의 개수를 추가/제거하기 위해 사용될 수 있습니다.
* @type {VirtualManager}
* @property {function} renderPanel A rendering function for the panel element's innerHTML<ko>패널 엘리먼트의 innerHTML을 렌더링하는 함수</ko>
* @property {number} initialPanelCount Initial panel count to render<ko>최초로 렌더링할 패널의 개수</ko>
* @property {boolean} [cache=false] Whether to cache rendered panel's innerHTML<ko>렌더링된 패널의 innerHTML 정보를 캐시할지 여부</ko>
* @property {string} [panelClass="flicking-panel"] The class name that will be applied to rendered panel elements<ko>렌더링되는 패널 엘리먼트에 적용될 클래스 이름</ko>
* @see {@link https://naver.github.io/egjs-flicking/Options#virtual virtual ( Options )}
* @example
* ```ts
* import Flicking, { VirtualPanel } from "@egjs/flicking";
*
* const flicking = new Flicking("#some_el", {
* panelsPerView: 3,
* virtual: {
* renderPanel: (panel: VirtualPanel, index: number) => `Panel ${index}`,
* initialPanelCount: 100
* }
* });
*
* // Add 100 virtual panels (at the end)
* flicking.virtual.append(100);
*
* // Remove 100 virtual panels from 0 to 100
* flicking.virtual.remove(0, 100);
* ```
*/
public get virtual() { return this._virtualManager; }
// OTHERS
/**
* Call {@link Flicking#init init()} automatically when creating Flicking's instance
* @ko Flicking 인스턴스를 생성할 때 자동으로 {@link Flicking#init init()}를 호출합니다
* @type {boolean}
* @default true
* @see {@link https://naver.github.io/egjs-flicking/Options#autoinit autoInit ( Options )}
* @readonly
*/
public get autoInit() { return this._autoInit; }
/**
* Whether to automatically call {@link Flicking#resize resize()} when the viewport element(.flicking-viewport)'s size is changed
* @ko 뷰포트 엘리먼트(.flicking-viewport)의 크기 변경시 {@link Flicking#resize resize()} 메소드를 자동으로 호출할지 여부를 설정합니다
* @type {boolean}
* @default true
*/
public get autoResize() { return this._autoResize; }
/**
* Whether to listen {@link https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserver ResizeObserver}'s event instead of Window's {@link https://developer.mozilla.org/ko/docs/Web/API/Window/resize_event resize} event when using the `autoResize` option
* @ko autoResize 옵션 사용시 {@link https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserver ResizeObserver}의 이벤트를 Window객체의 {@link https://developer.mozilla.org/ko/docs/Web/API/Window/resize_event resize} 이벤트 대신 수신할지 여부를 설정합니다
* @type {boolean}
* @default true
* @see {@link https://naver.github.io/egjs-flicking/Options#useresizeobserver useResizeObserver ( Options )}
*/
public get useResizeObserver() { return this._useResizeObserver; }
/**
* Delays size recalculation from `autoResize` by the given time in milisecond.
* If the size is changed again while being delayed, it cancels the previous one and delays from the beginning again.
* This can increase performance by preventing `resize` being called too often.
* @ko `autoResize` 설정시에 호출되는 크기 재계산을 주어진 시간(단위: ms)만큼 지연시킵니다.
* 지연시키는 도중 크기가 다시 변경되었을 경우, 이전 것을 취소하고 주어진 시간만큼 다시 지연시킵니다.
* 이를 통해 `resize`가 너무 많이 호출되는 것을 방지하여 성능을 향상시킬 수 있습니다.
* @type {number}
* @default 0
* @see {@link https://naver.github.io/egjs-flicking/Options#resizedebounce resizeDebounce ( Options )}
*/
public get resizeDebounce() { return this._resizeDebounce; }
/**
* The maximum time for size recalculation delay when using `resizeDebounce`, in milisecond.
* This guarantees that size recalculation is performed at least once every (n)ms.
* @ko `resizeDebounce` 사용시에 크기 재계산이 지연되는 최대 시간을 지정합니다. (단위: ms)
* 이를 통해, 적어도 (n)ms에 한번은 크기 재계산을 수행하는 것을 보장할 수 있습니다.
* @type {number}
* @default 100
* @see {@link https://naver.github.io/egjs-flicking/Options#maxresizedebounce maxResizeDebounce ( Options )}
*/
public get maxResizeDebounce() { return this._maxResizeDebounce; }
/**
* By enabling this, Flicking will calculate all internal size with CSS width computed with getComputedStyle.
* This can prevent 1px offset issue in some cases where panel size has the fractional part.
* All sizes will have the original size before CSS {@link https://developer.mozilla.org/en-US/docs/Web/CSS/transform transform} is applied on the element.
* @ko 이 옵션을 활성화할 경우, Flicking은 내부의 모든 크기를 {@link https://developer.mozilla.org/en-US/docs/Web/API/Element/getBoundingClientRect getBoundingClientRect}를 이용하여 계산합니다.
* 이를 통해, 패널 크기에 소수점을 포함할 경우에 발생할 수 있는 일부 1px 오프셋 이슈를 해결 가능합니다.
* 모든 크기는 CSS {@link https://developer.mozilla.org/en-US/docs/Web/CSS/transform transform}이 엘리먼트에 적용되기 이전의 크기를 사용할 것입니다.
* @type {boolean}
* @default false
* @see {@link https://naver.github.io/egjs-flicking/Options#usefractionalsize useFractionalSize ( Options )}
*/
public get useFractionalSize() { return this._useFractionalSize; }
/**
* This is an option for the frameworks(React, Vue, Angular, ...). Don't set it as it's automatically managed by Flicking.
* @ko 프레임워크(React, Vue, Angular, ...)에서만 사용하는 옵션으로, 자동으로 설정되므로 따로 사용하실 필요 없습니다!
* @default null
* @internal
* @readonly
*/
public get externalRenderer() { return this._externalRenderer; }
/**
* This is an option for the frameworks(React, Vue, Angular, ...). Don't set it as it's automatically managed by Flicking.
* @ko 프레임워크(React, Vue, Angular, ...)에서만 사용하는 옵션으로, 자동으로 설정되므로 따로 사용하실 필요 없습니다!
* @default null
* @internal
* @readonly
* @deprecated
*/
public get renderExternal() { return this._renderExternal; }
// Options Setter
// UI / LAYOUT
public set align(val: FlickingOptions["align"]) {
this._align = val;
this._renderer.align = val;
this._camera.align = val;
void this.resize();
}
public set defaultIndex(val: FlickingOptions["defaultIndex"]) { this._defaultIndex = val; }
public set horizontal(val: FlickingOptions["horizontal"]) {
this._horizontal = val;
this._control.controller.updateDirection();
void this.resize();
}
public set circular(val: FlickingOptions["circular"]) {
this._circular = val;
void this.resize();
}
public set bound(val: FlickingOptions["bound"]) {
this._bound = val;
void this.resize();
}
public set adaptive(val: FlickingOptions["adaptive"]) {
this._adaptive = val;
void this.resize();
}
public set panelsPerView(val: FlickingOptions["panelsPerView"]) {
this._panelsPerView = val;
void this.resize();
}
public set noPanelStyleOverride(val: FlickingOptions["noPanelStyleOverride"]) {
this._noPanelStyleOverride = val;
void this.resize();
}
public set resizeOnContentsReady(val: FlickingOptions["resizeOnContentsReady"]) {
this._resizeOnContentsReady = val;
if (val) {
this._renderer.checkPanelContentsReady(this._renderer.panels);
}
}
public set nested(val: FlickingOptions["nested"]) {
this._nested = val;
const axes = this._control.controller.axes;
if (axes) {
axes.options.nested = val;
}
}
// EVENTS
public set needPanelThreshold(val: FlickingOptions["needPanelThreshold"]) { this._needPanelThreshold = val; }
public set preventEventsBeforeInit(val: FlickingOptions["preventEventsBeforeInit"]) { this._preventEventsBeforeInit = val; }
// ANIMATION
public set deceleration(val: FlickingOptions["deceleration"]) {
this._deceleration = val;
const axes = this._control.controller.axes;
if (axes) {
axes.options.deceleration = val;
}
}
public set easing(val: FlickingOptions["easing"]) {
this._easing = val;
const axes = this._control.controller.axes;
if (axes) {
axes.options.easing = val;
}
}
public set duration(val: FlickingOptions["duration"]) { this._duration = val; }
// INPUT
public set inputType(val: FlickingOptions["inputType"]) {
this._inputType = val;
const panInput = this._control.controller.panInput;
if (panInput) {
panInput.options.inputType = val;
}
}
public set moveType(val: FlickingOptions["moveType"]) {
this._moveType = val;
const prevControl = this._control;
const newControl = this._createControl();
const activePanel = prevControl.activePanel;
newControl.copy(prevControl);
const prevProgressInPanel = activePanel
? this._camera.getProgressInPanel(activePanel)
: 0;
this._control = newControl;
this._control.updatePosition(prevProgressInPanel);
this._control.updateInput();
}
public set threshold(val: FlickingOptions["threshold"]) { this._threshold = val; }
public set interruptable(val: FlickingOptions["interruptable"]) {
this._interruptable = val;
const axes = this._control.controller.axes;
if (axes) {
axes.options.interruptable = val;
}
}
public set bounce(val: FlickingOptions["bounce"]) {
this._bounce = val;
this._control.updateInput();
}
public set iOSEdgeSwipeThreshold(val: FlickingOptions["iOSEdgeSwipeThreshold"]) {
this._iOSEdgeSwipeThreshold = val;
const panInput = this._control.controller.panInput;
if (panInput) {
panInput.options.iOSEdgeSwipeThreshold = val;
}
}
public set preventClickOnDrag(val: FlickingOptions["preventClickOnDrag"]) {
const prevVal = this._preventClickOnDrag;
if (val === prevVal) return;
const controller = this._control.controller;
if (val) {
controller.addPreventClickHandler();
} else {
controller.removePreventClickHandler();
}
this._preventClickOnDrag = val;
}
public set preventDefaultOnDrag(val: FlickingOptions["preventDefaultOnDrag"]) {
this._preventDefaultOnDrag = val;
const panInput = this._control.controller.panInput;
if (panInput) {
panInput.options.preventDefaultOnDrag = val;
}
}
public set disableOnInit(val: FlickingOptions["disableOnInit"]) { this._disableOnInit = val; }
public set changeOnHold(val: FlickingOptions["changeOnHold"]) { this._changeOnHold = val; }
// PERFORMANCE
public set renderOnlyVisible(val: FlickingOptions["renderOnlyVisible"]) {
this._renderOnlyVisible = val;
void this._renderer.render();
}
// OTHERS
public set autoResize(val: FlickingOptions["autoResize"]) {
this._autoResize = val;
if (val) {
this._autoResizer.enable();
} else {
this._autoResizer.disable();
}
}
public set useResizeObserver(val: FlickingOptions["useResizeObserver"]) {
this._useResizeObserver = val;
if (this._autoResize) {
this._autoResizer.enable();
}
}
/**
* @param root A root HTMLElement to initialize Flicking on it. When it's a typeof `string`, it should be a css selector string
* <ko>Flicking을 초기화할 HTMLElement로, `string` 타입으로 지정시 css 선택자 문자열을 지정해야 합니다.</ko>
* @param {object} [options={}] An options object for Flicking.<ko>Flicking에 적용할 옵션 오브젝트</ko>
* @throws {FlickingError}
* |code|condition|
* |---|---|
* |{@link ERROR_CODE WRONG_TYPE}|When the root is not either string or HTMLElement|
* |{@link ERROR_CODE ELEMENT_NOT_FOUND}|When the element with given CSS selector does not exist|
* <ko>
*
* |code|조건|
* |---|---|
* |{@link ERROR_CODE WRONG_TYPE}|루트 엘리먼트가 string이나 HTMLElement가 아닐 경우|
* |{@link ERROR_CODE ELEMENT_NOT_FOUND}|주어진 CSS selector로 엘리먼트를 찾지 못했을 경우|
*
* </ko>
* @example
* ```ts
* import Flicking from "@egjs/flicking";
*
* // Creating new instance of Flicking with HTMLElement
* const flicking = new Flicking(document.querySelector(".flicking-viewport"), { circular: true });
*
* // Creating new instance of Flicking with CSS selector
* const flicking2 = new Flicking(".flicking-viewport", { circular: true });
* ```
*/
public constructor(root: HTMLElement | string, {
align = ALIGN.CENTER,
defaultIndex = 0,
horizontal = true,
circular = false,
circularFallback = CIRCULAR_FALLBACK.LINEAR,
bound = false,
adaptive = false,
panelsPerView = -1,
noPanelStyleOverride = false,
resizeOnContentsReady = false,
nested = false,
needPanelThreshold = 0,
preventEventsBeforeInit = true,
deceleration = 0.0075,
duration = 500,
easing = x => 1 - Math.pow(1 - x, 3),
inputType = ["mouse", "touch"],
moveType = "snap",
threshold = 40,
interruptable = true,
bounce = "20%",
iOSEdgeSwipeThreshold = 30,
preventClickOnDrag = true,
preventDefaultOnDrag = false,
disableOnInit = false,
changeOnHold = false,
renderOnlyVisible = false,
virtual = null,
autoInit = true,
autoResize = true,
useResizeObserver = true,
resizeDebounce = 0,
maxResizeDebounce = 100,
useFractionalSize = false,
externalRenderer = null,
renderExternal = null
}: Partial<FlickingOptions> = {}) {
super();
// Internal states
this._initialized = false;
this._plugins = [];
// Bind options
this._align = align;
this._defaultIndex = defaultIndex;
this._horizontal = horizontal;
this._circular = circular;