@egjs/flicking 4.3.1 → 4.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (92) hide show
  1. package/README.md +1 -2
  2. package/declaration/Flicking.d.ts +30 -12
  3. package/declaration/camera/Camera.d.ts +29 -26
  4. package/declaration/camera/index.d.ts +2 -4
  5. package/declaration/camera/mode/BoundCameraMode.d.ts +13 -0
  6. package/declaration/camera/mode/CameraMode.d.ts +19 -0
  7. package/declaration/camera/mode/CircularCameraMode.d.ts +18 -0
  8. package/declaration/camera/mode/LinearCameraMode.d.ts +9 -0
  9. package/declaration/camera/mode/index.d.ts +6 -0
  10. package/declaration/const/error.d.ts +3 -1
  11. package/declaration/const/external.d.ts +9 -0
  12. package/declaration/core/AutoResizer.d.ts +13 -0
  13. package/declaration/core/VirtualManager.d.ts +37 -0
  14. package/declaration/core/index.d.ts +2 -1
  15. package/declaration/core/panel/Panel.d.ts +13 -7
  16. package/declaration/core/panel/VirtualPanel.d.ts +19 -0
  17. package/declaration/core/panel/index.d.ts +4 -4
  18. package/declaration/core/panel/provider/ElementProvider.d.ts +8 -0
  19. package/declaration/core/panel/provider/VanillaElementProvider.d.ts +12 -0
  20. package/declaration/core/panel/provider/VirtualElementProvider.d.ts +15 -0
  21. package/declaration/core/panel/provider/index.d.ts +5 -0
  22. package/declaration/index.d.ts +11 -1
  23. package/declaration/renderer/ExternalRenderer.d.ts +1 -1
  24. package/declaration/renderer/Renderer.d.ts +17 -12
  25. package/declaration/renderer/VanillaRenderer.d.ts +2 -7
  26. package/declaration/renderer/index.d.ts +1 -0
  27. package/declaration/renderer/strategy/NormalRenderingStrategy.d.ts +23 -0
  28. package/declaration/renderer/strategy/RenderingStrategy.d.ts +15 -0
  29. package/declaration/renderer/strategy/VirtualRenderingStrategy.d.ts +17 -0
  30. package/declaration/renderer/strategy/index.d.ts +5 -0
  31. package/declaration/type/external.d.ts +1 -3
  32. package/declaration/utils.d.ts +7 -1
  33. package/dist/flicking.esm.js +2526 -1475
  34. package/dist/flicking.esm.js.map +1 -1
  35. package/dist/flicking.js +2561 -1485
  36. package/dist/flicking.js.map +1 -1
  37. package/dist/flicking.min.js +2 -2
  38. package/dist/flicking.min.js.map +1 -1
  39. package/dist/flicking.pkgd.js +9006 -8312
  40. package/dist/flicking.pkgd.js.map +1 -1
  41. package/dist/flicking.pkgd.min.js +2 -2
  42. package/dist/flicking.pkgd.min.js.map +1 -1
  43. package/package.json +12 -24
  44. package/src/Flicking.ts +172 -45
  45. package/src/camera/Camera.ts +201 -93
  46. package/src/camera/index.ts +3 -7
  47. package/src/camera/{BoundCamera.ts → mode/BoundCameraMode.ts} +46 -43
  48. package/src/camera/mode/CameraMode.ts +77 -0
  49. package/src/camera/mode/CircularCameraMode.ts +171 -0
  50. package/src/camera/mode/LinearCameraMode.ts +23 -0
  51. package/src/camera/mode/index.ts +14 -0
  52. package/src/cfc/sync.ts +10 -5
  53. package/src/const/error.ts +6 -3
  54. package/src/const/external.ts +18 -0
  55. package/src/control/AxesController.ts +11 -6
  56. package/src/control/Control.ts +6 -6
  57. package/src/control/FreeControl.ts +2 -2
  58. package/src/control/SnapControl.ts +3 -3
  59. package/src/control/StrictControl.ts +2 -2
  60. package/src/core/AutoResizer.ts +81 -0
  61. package/src/core/Viewport.ts +4 -4
  62. package/src/core/VirtualManager.ts +188 -0
  63. package/src/core/index.ts +3 -1
  64. package/src/core/panel/Panel.ts +54 -34
  65. package/src/core/panel/VirtualPanel.ts +110 -0
  66. package/src/core/panel/index.ts +5 -7
  67. package/src/core/panel/provider/ElementProvider.ts +14 -0
  68. package/src/core/panel/provider/VanillaElementProvider.ts +45 -0
  69. package/src/core/panel/provider/VirtualElementProvider.ts +48 -0
  70. package/src/core/panel/provider/index.ts +16 -0
  71. package/src/index.ts +12 -1
  72. package/src/index.umd.ts +2 -0
  73. package/src/renderer/ExternalRenderer.ts +7 -7
  74. package/src/renderer/Renderer.ts +106 -65
  75. package/src/renderer/VanillaRenderer.ts +28 -86
  76. package/src/renderer/index.ts +2 -0
  77. package/src/renderer/strategy/NormalRenderingStrategy.ts +106 -0
  78. package/src/renderer/strategy/RenderingStrategy.ts +21 -0
  79. package/src/renderer/strategy/VirtualRenderingStrategy.ts +110 -0
  80. package/src/renderer/strategy/index.ts +17 -0
  81. package/src/utils.ts +36 -2
  82. package/declaration/camera/BoundCamera.d.ts +0 -9
  83. package/declaration/camera/CircularCamera.d.ts +0 -36
  84. package/declaration/camera/LinearCamera.d.ts +0 -5
  85. package/declaration/core/panel/ElementPanel.d.ts +0 -14
  86. package/declaration/core/panel/ExternalPanel.d.ts +0 -9
  87. package/declaration/exports.d.ts +0 -10
  88. package/src/camera/CircularCamera.ts +0 -269
  89. package/src/camera/LinearCamera.ts +0 -35
  90. package/src/core/panel/ElementPanel.ts +0 -52
  91. package/src/core/panel/ExternalPanel.ts +0 -32
  92. package/src/exports.ts +0 -16
@@ -9,8 +9,10 @@ import FlickingError from "../core/FlickingError";
9
9
  import Panel from "../core/panel/Panel";
10
10
  import AnchorPoint from "../core/AnchorPoint";
11
11
  import * as ERROR from "../const/error";
12
- import { ALIGN, DIRECTION, EVENTS } from "../const/external";
13
- import { checkExistence, clamp, find, getFlickingAttached, getProgress, includes, parseAlign } from "../utils";
12
+ import { ALIGN, CIRCULAR_FALLBACK, DIRECTION, EVENTS } from "../const/external";
13
+ import { checkExistence, find, getFlickingAttached, getProgress, includes, parseAlign, toArray } from "../utils";
14
+
15
+ import { CameraMode, BoundCameraMode, CircularCameraMode, LinearCameraMode } from "./mode";
14
16
 
15
17
  export interface CameraOptions {
16
18
  align: FlickingOptions["align"];
@@ -20,30 +22,40 @@ export interface CameraOptions {
20
22
  * A component that manages actual movement inside the viewport
21
23
  * @ko 뷰포트 내에서의 실제 움직임을 담당하는 컴포넌트
22
24
  */
23
- abstract class Camera {
25
+ class Camera {
24
26
  // Options
25
- protected _align: FlickingOptions["align"];
27
+ private _align: FlickingOptions["align"];
26
28
 
27
29
  // Internal states
28
- protected _flicking: Flicking | null;
29
- protected _el: HTMLElement;
30
- protected _transform: string;
31
- protected _position: number;
32
- protected _alignPos: number;
33
- protected _offset: number;
34
- protected _range: { min: number; max: number };
35
- protected _visiblePanels: Panel[];
36
- protected _anchors: AnchorPoint[];
37
- protected _needPanelTriggered: { prev: boolean; next: boolean };
30
+ private _flicking: Flicking | null;
31
+ private _mode: CameraMode;
32
+ private _el: HTMLElement;
33
+ private _transform: string;
34
+ private _position: number;
35
+ private _alignPos: number;
36
+ private _offset: number;
37
+ private _circularOffset: number;
38
+ private _circularEnabled: boolean;
39
+ private _range: { min: number; max: number };
40
+ private _visiblePanels: Panel[];
41
+ private _anchors: AnchorPoint[];
42
+ private _needPanelTriggered: { prev: boolean; next: boolean };
38
43
 
39
44
  // Internal states getter
40
45
  /**
41
- * The camera(`.flicking-camera`) element
42
- * @ko 카메라(`.flicking-camera`) 엘리먼트
46
+ * The camera element(`.flicking-camera`)
47
+ * @ko 카메라 엘리먼트(`.flicking-camera`)
43
48
  * @type {HTMLElement}
44
49
  * @readonly
45
50
  */
46
51
  public get element() { return this._el; }
52
+ /**
53
+ * An array of the child elements of the camera element(`.flicking-camera`)
54
+ * @ko 카메라 엘리먼트(`.flicking-camera`)의 자식 엘리먼트 배열
55
+ * @type {HTMLElement[]}
56
+ * @readonly
57
+ */
58
+ public get children() { return toArray(this._el.children) as HTMLElement[]; }
47
59
  /**
48
60
  * Current position of the camera
49
61
  * @ko Camera의 현재 좌표
@@ -65,13 +77,29 @@ abstract class Camera {
65
77
  * @default 0
66
78
  * @readonly
67
79
  */
68
- public get offset() { return this._offset; }
80
+ public get offset() { return this._offset - this._circularOffset; }
81
+ /**
82
+ * Whether the `circular` option is enabled.
83
+ * The {@link Flicking#circular circular} option can't be enabled when sum of the panel sizes are too small.
84
+ * @ko {@link Flicking#circular circular} 옵션이 활성화되었는지 여부를 나타내는 멤버 변수.
85
+ * {@link Flicking#circular circular} 옵션은 패널의 크기의 합이 충분하지 않을 경우 비활성화됩니다.
86
+ * @type {boolean}
87
+ * @default false
88
+ * @readonly
89
+ */
90
+ public get circularEnabled() { return this._circularEnabled; }
91
+ /**
92
+ * A current camera mode
93
+ * @type {CameraMode}
94
+ * @readonly
95
+ */
96
+ public get mode() { return this._mode; }
69
97
  /**
70
98
  * A range that Camera's {@link Camera#position position} can reach
71
99
  * @ko Camera의 {@link Camera#position position}이 도달 가능한 범위
72
100
  * @type {object}
73
101
  * @property {number} min A minimum position<ko>최소 위치</ko>
74
- * @property {number} min A maximum position<ko>최대 위치</ko>
102
+ * @property {number} max A maximum position<ko>최대 위치</ko>
75
103
  * @readonly
76
104
  */
77
105
  public get range() { return this._range; }
@@ -111,7 +139,7 @@ abstract class Camera {
111
139
  * @type {ControlParams}
112
140
  * @readonly
113
141
  */
114
- public get controlParams() { return { range: this._range, position: this._position, circular: false }; }
142
+ public get controlParams() { return { range: this._range, position: this._position, circular: this._circularEnabled }; }
115
143
  /**
116
144
  * A Boolean value indicating whether Camera's over the minimum or maximum position reachable
117
145
  * @ko 현재 카메라가 도달 가능한 범위의 최소 혹은 최대점을 넘어섰는지를 나타냅니다
@@ -213,22 +241,6 @@ abstract class Camera {
213
241
  this._align = align;
214
242
  }
215
243
 
216
- /**
217
- * Update {@link Camera#range range} of Camera
218
- * @ko Camera의 {@link Camera#range range}를 업데이트합니다
219
- * @method
220
- * @abstract
221
- * @memberof Camera
222
- * @instance
223
- * @name updateRange
224
- * @chainable
225
- * @throws {FlickingError}
226
- * {@link ERROR_CODE NOT_ATTACHED_TO_FLICKING} When {@link Camera#init init} is not called before
227
- * <ko>{@link ERROR_CODE NOT_ATTACHED_TO_FLICKING} {@link Camera#init init}이 이전에 호출되지 않은 경우</ko>
228
- * @return {this}
229
- */
230
- public abstract updateRange(): this;
231
-
232
244
  /**
233
245
  * Initialize Camera
234
246
  * @ko Camera를 초기화합니다
@@ -248,6 +260,8 @@ abstract class Camera {
248
260
  this._el = viewportEl.firstElementChild as HTMLElement;
249
261
  this._checkTranslateSupport();
250
262
 
263
+ this._updateMode();
264
+
251
265
  return this;
252
266
  }
253
267
 
@@ -272,13 +286,21 @@ abstract class Camera {
272
286
  * @return {this}
273
287
  */
274
288
  public lookAt(pos: number): void {
289
+ const flicking = getFlickingAttached(this._flicking);
275
290
  const prevPos = this._position;
276
291
 
277
292
  this._position = pos;
293
+ const toggled = this._togglePanels(prevPos, pos);
278
294
  this._refreshVisiblePanels();
279
295
  this._checkNeedPanel();
280
296
  this._checkReachEnd(prevPos, pos);
281
- this._applyTransform();
297
+ this.applyTransform();
298
+
299
+ if (toggled) {
300
+ void flicking.renderer.render().then(() => {
301
+ this.updateOffset();
302
+ });
303
+ }
282
304
  }
283
305
 
284
306
  /**
@@ -290,7 +312,19 @@ abstract class Camera {
290
312
  * @return {AnchorPoint | null} The previous {@link AnchorPoint}<ko>이전 {@link AnchorPoint}</ko>
291
313
  */
292
314
  public getPrevAnchor(anchor: AnchorPoint): AnchorPoint | null {
293
- return this._anchors[anchor.index - 1] || null;
315
+ if (!this._circularEnabled || anchor.index !== 0) {
316
+ return this._anchors[anchor.index - 1] || null;
317
+ } else {
318
+ const anchors = this._anchors;
319
+ const rangeDiff = this.rangeDiff;
320
+ const lastAnchor = anchors[anchors.length - 1];
321
+
322
+ return new AnchorPoint({
323
+ index: lastAnchor.index,
324
+ position: lastAnchor.position - rangeDiff,
325
+ panel: lastAnchor.panel
326
+ });
327
+ }
294
328
  }
295
329
 
296
330
  /**
@@ -302,7 +336,20 @@ abstract class Camera {
302
336
  * @return {AnchorPoint | null} The next {@link AnchorPoint}<ko>다음 {@link AnchorPoint}</ko>
303
337
  */
304
338
  public getNextAnchor(anchor: AnchorPoint): AnchorPoint | null {
305
- return this._anchors[anchor.index + 1] || null;
339
+ const anchors = this._anchors;
340
+
341
+ if (!this._circularEnabled || anchor.index !== anchors.length - 1) {
342
+ return anchors[anchor.index + 1] || null;
343
+ } else {
344
+ const rangeDiff = this.rangeDiff;
345
+ const firstAnchor = anchors[0];
346
+
347
+ return new AnchorPoint({
348
+ index: firstAnchor.index,
349
+ position: firstAnchor.position + rangeDiff,
350
+ panel: firstAnchor.panel
351
+ });
352
+ }
306
353
  }
307
354
 
308
355
  /**
@@ -328,16 +375,7 @@ abstract class Camera {
328
375
  * @return {AnchorPoint | null} The {@link AnchorPoint} that includes the given position<ko>해당 좌표를 포함하는 {@link AnchorPoint}</ko>
329
376
  */
330
377
  public findAnchorIncludePosition(position: number): AnchorPoint | null {
331
- const anchors = this._anchors;
332
- const anchorsIncludingPosition = anchors.filter(anchor => anchor.panel.includePosition(position, true));
333
-
334
- return anchorsIncludingPosition.reduce((nearest: AnchorPoint | null, anchor) => {
335
- if (!nearest) return anchor;
336
-
337
- return Math.abs(nearest.position - position) < Math.abs(anchor.position - position)
338
- ? nearest
339
- : anchor;
340
- }, null);
378
+ return this._mode.findAnchorIncludePosition(position);
341
379
  }
342
380
 
343
381
  /**
@@ -376,7 +414,7 @@ abstract class Camera {
376
414
  * @return {AnchorPoint | null}
377
415
  */
378
416
  public findActiveAnchor(): AnchorPoint | null {
379
- const flicking = getFlickingAttached(this._flicking, "Camera");
417
+ const flicking = getFlickingAttached(this._flicking);
380
418
  const activeIndex = flicking.control.activeIndex;
381
419
 
382
420
  return find(this._anchors, anchor => anchor.panel.index === activeIndex);
@@ -389,8 +427,7 @@ abstract class Camera {
389
427
  * @return {number} A clamped position<ko>범위 제한된 좌표</ko>
390
428
  */
391
429
  public clampToReachablePosition(position: number): number {
392
- const range = this._range;
393
- return clamp(position, range.min, range.max);
430
+ return this._mode.clampToReachablePosition(position);
394
431
  }
395
432
 
396
433
  /**
@@ -400,13 +437,7 @@ abstract class Camera {
400
437
  * @return {boolean} Whether the panel's inside Camera's range<ko>도달 가능한 범위 내에 해당 패널이 존재하는지 여부</ko>
401
438
  */
402
439
  public canReach(panel: Panel): boolean {
403
- const range = this._range;
404
-
405
- if (panel.removed) return false;
406
-
407
- const panelPos = panel.position;
408
-
409
- return panelPos >= range.min && panelPos <= range.max;
440
+ return this._mode.canReach(panel);
410
441
  }
411
442
 
412
443
  /**
@@ -416,9 +447,38 @@ abstract class Camera {
416
447
  * @return Whether the panel element is visible at the current position<ko>현재 위치에서 해당 패널 엘리먼트가 보이는지 여부</ko>
417
448
  */
418
449
  public canSee(panel: Panel): boolean {
419
- const visibleRange = this.visibleRange;
420
- // Should not include margin, as we don't declare what the margin is visible as what the panel is visible.
421
- return panel.includeRange(visibleRange.min, visibleRange.max, false);
450
+ return this._mode.canSee(panel);
451
+ }
452
+
453
+ /**
454
+ * Update {@link Camera#range range} of Camera
455
+ * @ko Camera의 {@link Camera#range range}를 업데이트합니다
456
+ * @method
457
+ * @abstract
458
+ * @memberof Camera
459
+ * @instance
460
+ * @name updateRange
461
+ * @chainable
462
+ * @throws {FlickingError}
463
+ * {@link ERROR_CODE NOT_ATTACHED_TO_FLICKING} When {@link Camera#init init} is not called before
464
+ * <ko>{@link ERROR_CODE NOT_ATTACHED_TO_FLICKING} {@link Camera#init init}이 이전에 호출되지 않은 경우</ko>
465
+ * @return {this}
466
+ */
467
+ public updateRange() {
468
+ const flicking = getFlickingAttached(this._flicking);
469
+ const renderer = flicking.renderer;
470
+ const panels = renderer.panels;
471
+
472
+ this._updateMode();
473
+ this._range = this._mode.getRange();
474
+
475
+ if (this._circularEnabled) {
476
+ panels.forEach(panel => panel.updateCircularToggleDirection());
477
+ }
478
+
479
+ this.updateOffset();
480
+
481
+ return this;
422
482
  }
423
483
 
424
484
  /**
@@ -449,14 +509,7 @@ abstract class Camera {
449
509
  * @return {this}
450
510
  */
451
511
  public updateAnchors(): this {
452
- const flicking = getFlickingAttached(this._flicking, "Camera");
453
- const panels = flicking.renderer.panels;
454
-
455
- this._anchors = panels.map((panel, index) => new AnchorPoint({
456
- index,
457
- position: panel.position,
458
- panel
459
- }));
512
+ this._anchors = this._mode.getAnchors();
460
513
 
461
514
  return this;
462
515
  }
@@ -471,7 +524,7 @@ abstract class Camera {
471
524
  * @return {this}
472
525
  */
473
526
  public updateAdaptiveHeight() {
474
- const flicking = getFlickingAttached(this._flicking, "Camera");
527
+ const flicking = getFlickingAttached(this._flicking);
475
528
  const activePanel = flicking.control.activePanel;
476
529
 
477
530
  if (!flicking.horizontal || !flicking.adaptive || !activePanel) return;
@@ -481,16 +534,26 @@ abstract class Camera {
481
534
  });
482
535
  }
483
536
 
484
- public updateOffset() {
485
- const flicking = getFlickingAttached(this._flicking, "Camera");
486
- const unRenderedPanels = flicking.panels.filter(panel => !panel.rendered);
537
+ /**
538
+ * Update current offset of the camera
539
+ * @ko 현재 카메라의 오프셋을 업데이트합니다
540
+ * @chainable
541
+ * @return {this}
542
+ */
543
+ public updateOffset(): this {
544
+ const flicking = getFlickingAttached(this._flicking);
487
545
  const position = this._position;
546
+ const unRenderedPanels = flicking.panels.filter(panel => !panel.rendered);
488
547
 
489
548
  this._offset = unRenderedPanels
490
549
  .filter(panel => panel.position + panel.offset < position)
491
550
  .reduce((offset, panel) => offset + panel.sizeIncludingMargin, 0);
492
551
 
493
- this._applyTransform();
552
+ this._circularOffset = this._mode.getCircularOffset();
553
+
554
+ this.applyTransform();
555
+
556
+ return this;
494
557
  }
495
558
 
496
559
  /**
@@ -504,18 +567,39 @@ abstract class Camera {
504
567
  return this;
505
568
  }
506
569
 
507
- protected _resetInternalValues() {
570
+ /**
571
+ * Apply "transform" style with the current position to camera element
572
+ * @ko 현재 위치를 기준으로한 transform 스타일을 카메라 엘리먼트에 적용합니다.
573
+ * @chainable
574
+ * @return {this}
575
+ */
576
+ public applyTransform(): this {
577
+ const el = this._el;
578
+ const flicking = getFlickingAttached(this._flicking);
579
+
580
+ const actualPosition = this._position - this._alignPos - this._offset + this._circularOffset;
581
+
582
+ el.style[this._transform] = flicking.horizontal
583
+ ? `translate(${-actualPosition}px)`
584
+ : `translate(0, ${-actualPosition}px)`;
585
+
586
+ return this;
587
+ }
588
+
589
+ private _resetInternalValues() {
508
590
  this._position = 0;
509
591
  this._alignPos = 0;
510
592
  this._offset = 0;
593
+ this._circularOffset = 0;
594
+ this._circularEnabled = false;
511
595
  this._range = { min: 0, max: 0 };
512
596
  this._visiblePanels = [];
513
597
  this._anchors = [];
514
598
  this._needPanelTriggered = { prev: false, next: false };
515
599
  }
516
600
 
517
- protected _refreshVisiblePanels() {
518
- const flicking = getFlickingAttached(this._flicking, "Camera");
601
+ private _refreshVisiblePanels() {
602
+ const flicking = getFlickingAttached(this._flicking);
519
603
  const panels = flicking.renderer.panels;
520
604
 
521
605
  const newVisiblePanels = panels.filter(panel => this.canSee(panel));
@@ -536,12 +620,12 @@ abstract class Camera {
536
620
  }
537
621
  }
538
622
 
539
- protected _checkNeedPanel(): void {
623
+ private _checkNeedPanel(): void {
540
624
  const needPanelTriggered = this._needPanelTriggered;
541
625
 
542
626
  if (needPanelTriggered.prev && needPanelTriggered.next) return;
543
627
 
544
- const flicking = getFlickingAttached(this._flicking, "Camera");
628
+ const flicking = getFlickingAttached(this._flicking);
545
629
  const panels = flicking.renderer.panels;
546
630
 
547
631
  if (panels.length <= 0) {
@@ -587,8 +671,8 @@ abstract class Camera {
587
671
  }
588
672
  }
589
673
 
590
- protected _checkReachEnd(prevPos: number, newPos: number): void {
591
- const flicking = getFlickingAttached(this._flicking, "Camera");
674
+ private _checkReachEnd(prevPos: number, newPos: number): void {
675
+ const flicking = getFlickingAttached(this._flicking);
592
676
  const range = this._range;
593
677
 
594
678
  const wasBetweenRange = prevPos > range.min && prevPos < range.max;
@@ -603,18 +687,7 @@ abstract class Camera {
603
687
  }));
604
688
  }
605
689
 
606
- protected _applyTransform(): void {
607
- const el = this._el;
608
- const flicking = getFlickingAttached(this._flicking, "Camera");
609
-
610
- const actualPosition = this._position - this._alignPos - this._offset;
611
-
612
- el.style[this._transform] = flicking.horizontal
613
- ? `translate(${-actualPosition}px)`
614
- : `translate(0, ${-actualPosition}px)`;
615
- }
616
-
617
- protected _checkTranslateSupport = () => {
690
+ private _checkTranslateSupport = () => {
618
691
  const transforms = ["webkitTransform", "msTransform", "MozTransform", "OTransform", "transform"];
619
692
 
620
693
  const supportedStyle = document.documentElement.style;
@@ -631,6 +704,41 @@ abstract class Camera {
631
704
 
632
705
  this._transform = transformName;
633
706
  };
707
+
708
+ private _updateMode() {
709
+ const flicking = getFlickingAttached(this._flicking);
710
+
711
+ if (flicking.circular) {
712
+ const circularMode = new CircularCameraMode(flicking);
713
+ const canSetCircularMode = circularMode.checkAvailability();
714
+
715
+ if (canSetCircularMode) {
716
+ this._mode = circularMode;
717
+ } else {
718
+ const fallbackMode = flicking.circularFallback;
719
+
720
+ this._mode = fallbackMode === CIRCULAR_FALLBACK.BOUND
721
+ ? new BoundCameraMode(flicking)
722
+ : new LinearCameraMode(flicking);
723
+ }
724
+
725
+ this._circularEnabled = canSetCircularMode;
726
+ } else {
727
+ this._mode = flicking.bound
728
+ ? new BoundCameraMode(flicking)
729
+ : new LinearCameraMode(flicking);
730
+ }
731
+ }
732
+
733
+ private _togglePanels(prevPos: number, pos: number): boolean {
734
+ if (pos === prevPos) return false;
735
+
736
+ const flicking = getFlickingAttached(this._flicking);
737
+ const panels = flicking.renderer.panels;
738
+ const toggled = panels.map(panel => panel.toggle(prevPos, pos));
739
+
740
+ return toggled.some(isToggled => isToggled);
741
+ }
634
742
  }
635
743
 
636
744
  export default Camera;
@@ -3,17 +3,13 @@
3
3
  * egjs projects are licensed under the MIT license
4
4
  */
5
5
  import Camera, { CameraOptions } from "./Camera";
6
- import LinearCamera from "./LinearCamera";
7
- import CircularCamera from "./CircularCamera";
8
- import BoundCamera from "./BoundCamera";
9
6
 
10
7
  export {
11
- Camera,
12
- LinearCamera,
13
- CircularCamera,
14
- BoundCamera
8
+ Camera
15
9
  };
16
10
 
17
11
  export type {
18
12
  CameraOptions
19
13
  };
14
+
15
+ export * from "./mode";
@@ -2,40 +2,46 @@
2
2
  * Copyright (c) 2015 NAVER Corp.
3
3
  * egjs projects are licensed under the MIT license
4
4
  */
5
- import Panel from "../core/panel/Panel";
6
- import AnchorPoint from "../core/AnchorPoint";
7
- import { getFlickingAttached, parseAlign } from "../utils";
5
+ import AnchorPoint from "../../core/AnchorPoint";
6
+ import Panel from "../../core/panel/Panel";
7
+ import { parseAlign } from "../../utils";
8
8
 
9
- import Camera from "./Camera";
9
+ import CameraMode from "./CameraMode";
10
10
 
11
- /**
12
- * A {@link Camera} that set range not to go out of the first/last panel, so it won't show empty spaces before/after the first/last panel
13
- * @ko 첫번째와 마지막 패널 밖으로 넘어가지 못하도록 범위를 설정하여, 첫번째/마지막 패널 전/후의 빈 공간을 보이지 않도록 하는 종류의 {@link Camera}
14
- */
15
- class BoundCamera extends Camera {
16
- /**
17
- * Update {@link Camera#range range} of Camera
18
- * @ko Camera의 {@link Camera#range range}를 업데이트합니다
19
- * @chainable
20
- * @throws {FlickingError}
21
- * {@link ERROR_CODE NOT_ATTACHED_TO_FLICKING} When {@link Camera#init init} is not called before
22
- * <ko>{@link ERROR_CODE NOT_ATTACHED_TO_FLICKING} {@link Camera#init init}이 이전에 호출되지 않은 경우</ko>
23
- * @return {this}
24
- */
25
- public updateRange() {
26
- const flicking = getFlickingAttached(this._flicking, "Camera");
11
+ class BoundCameraMode extends CameraMode {
12
+ public checkAvailability(): boolean {
13
+ const flicking = this._flicking;
14
+ const renderer = flicking.renderer;
15
+
16
+ const firstPanel = renderer.getPanel(0);
17
+ const lastPanel = renderer.getPanel(renderer.panelCount - 1);
18
+
19
+ if (!firstPanel || !lastPanel) {
20
+ return false;
21
+ }
22
+
23
+ const viewportSize = flicking.camera.size;
24
+ const firstPanelPrev = firstPanel.range.min;
25
+ const lastPanelNext = lastPanel.range.max;
26
+ const panelAreaSize = lastPanelNext - firstPanelPrev;
27
+ const isBiggerThanViewport = viewportSize < panelAreaSize;
28
+
29
+ return isBiggerThanViewport;
30
+ }
31
+
32
+ public getRange(): { min: number; max: number } {
33
+ const flicking = this._flicking;
27
34
  const renderer = flicking.renderer;
28
- const alignPos = this._alignPos;
35
+ const alignPos = flicking.camera.alignPosition;
29
36
 
30
37
  const firstPanel = renderer.getPanel(0);
31
38
  const lastPanel = renderer.getPanel(renderer.panelCount - 1);
32
39
 
33
40
  if (!firstPanel || !lastPanel) {
34
- this._range = { min: 0, max: 0 };
35
- return this;
41
+ return { min: 0, max: 0 };
36
42
  }
37
43
 
38
- const viewportSize = this.size;
44
+ const viewportSize = flicking.camera.size;
39
45
  const firstPanelPrev = firstPanel.range.min;
40
46
  const lastPanelNext = lastPanel.range.max;
41
47
  const panelAreaSize = lastPanelNext - firstPanelPrev;
@@ -45,32 +51,30 @@ class BoundCamera extends Camera {
45
51
  const lastPos = lastPanelNext - viewportSize + alignPos;
46
52
 
47
53
  if (isBiggerThanViewport) {
48
- this._range = { min: firstPos, max: lastPos };
54
+ return { min: firstPos, max: lastPos };
49
55
  } else {
50
- const align = this._align;
56
+ const align = flicking.camera.align;
51
57
  const alignVal = typeof align === "object"
52
58
  ? (align as { camera: string | number }).camera
53
59
  : align;
54
60
 
55
61
  const pos = firstPos + parseAlign(alignVal, lastPos - firstPos);
56
62
 
57
- this._range = { min: pos, max: pos };
63
+ return { min: pos, max: pos };
58
64
  }
59
-
60
- return this;
61
65
  }
62
66
 
63
- public updateAnchors(): this {
64
- const flicking = getFlickingAttached(this._flicking, "Camera");
67
+ public getAnchors(): AnchorPoint[] {
68
+ const flicking = this._flicking;
69
+ const camera = flicking.camera;
65
70
  const panels = flicking.renderer.panels;
66
71
 
67
72
  if (panels.length <= 0) {
68
- this._anchors = [];
69
- return this;
73
+ return [];
70
74
  }
71
75
 
72
- const range = this._range;
73
- const reachablePanels = panels.filter(panel => this.canReach(panel));
76
+ const range = flicking.camera.range;
77
+ const reachablePanels = panels.filter(panel => camera.canReach(panel));
74
78
 
75
79
  if (reachablePanels.length > 0) {
76
80
  const shouldPrependBoundAnchor = reachablePanels[0].position !== range.min;
@@ -99,7 +103,7 @@ class BoundCamera extends Camera {
99
103
  }));
100
104
  }
101
105
 
102
- this._anchors = newAnchors;
106
+ return newAnchors;
103
107
  } else if (range.min !== range.max) {
104
108
  // There're more than 2 panels
105
109
  const nearestPanelAtMin = this._findNearestPanel(range.min, panels);
@@ -108,7 +112,7 @@ class BoundCamera extends Camera {
108
112
  : nearestPanelAtMin;
109
113
  const panelAtMax = panelAtMin.next()!;
110
114
 
111
- this._anchors = [
115
+ return [
112
116
  new AnchorPoint({
113
117
  index: 0,
114
118
  position: range.min,
@@ -121,19 +125,18 @@ class BoundCamera extends Camera {
121
125
  })
122
126
  ];
123
127
  } else {
124
- this._anchors = [new AnchorPoint({
128
+ return [new AnchorPoint({
125
129
  index: 0,
126
130
  position: range.min,
127
131
  panel: this._findNearestPanel(range.min, panels)
128
132
  })];
129
133
  }
130
-
131
- return this;
132
134
  }
133
135
 
134
136
  public findAnchorIncludePosition(position: number): AnchorPoint | null {
135
- const range = this._range;
136
- const anchors = this._anchors;
137
+ const camera = this._flicking.camera;
138
+ const range = camera.range;
139
+ const anchors = camera.anchorPoints;
137
140
 
138
141
  if (anchors.length <= 0) return null;
139
142
 
@@ -165,4 +168,4 @@ class BoundCamera extends Camera {
165
168
  }
166
169
  }
167
170
 
168
- export default BoundCamera;
171
+ export default BoundCameraMode;