@egjs/flicking 4.4.2 → 4.6.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 (57) hide show
  1. package/TODO.md +3 -0
  2. package/declaration/Flicking.d.ts +15 -2
  3. package/declaration/camera/Camera.d.ts +28 -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/external.d.ts +4 -0
  11. package/declaration/control/StrictControl.d.ts +1 -0
  12. package/declaration/core/AutoResizer.d.ts +3 -0
  13. package/declaration/core/ResizeWatcher.d.ts +33 -0
  14. package/declaration/renderer/Renderer.d.ts +13 -0
  15. package/declaration/type/external.d.ts +1 -3
  16. package/{css → dist/css}/flicking-inline.css +20 -13
  17. package/dist/css/flicking-inline.min.css +1 -0
  18. package/dist/css/flicking.css +44 -0
  19. package/dist/css/flicking.min.css +1 -0
  20. package/dist/flicking.esm.js +1491 -1251
  21. package/dist/flicking.esm.js.map +1 -1
  22. package/dist/flicking.js +1494 -1253
  23. package/dist/flicking.js.map +1 -1
  24. package/dist/flicking.min.js +2 -2
  25. package/dist/flicking.min.js.map +1 -1
  26. package/dist/flicking.pkgd.js +1466 -1225
  27. package/dist/flicking.pkgd.js.map +1 -1
  28. package/dist/flicking.pkgd.min.js +2 -2
  29. package/dist/flicking.pkgd.min.js.map +1 -1
  30. package/package.json +17 -7
  31. package/sass/flicking-inline.sass +30 -0
  32. package/sass/flicking.sass +23 -0
  33. package/src/Flicking.ts +127 -35
  34. package/src/camera/Camera.ts +162 -81
  35. package/src/camera/index.ts +3 -7
  36. package/src/camera/{BoundCamera.ts → mode/BoundCameraMode.ts} +46 -43
  37. package/src/camera/mode/CameraMode.ts +77 -0
  38. package/src/camera/mode/CircularCameraMode.ts +171 -0
  39. package/src/camera/mode/LinearCameraMode.ts +23 -0
  40. package/src/camera/mode/index.ts +14 -0
  41. package/src/cfc/sync.ts +29 -23
  42. package/src/cfc/withFlickingMethods.ts +3 -2
  43. package/src/const/external.ts +12 -0
  44. package/src/control/StrictControl.ts +10 -0
  45. package/src/core/AutoResizer.ts +33 -0
  46. package/src/core/ResizeWatcher.ts +133 -0
  47. package/src/renderer/Renderer.ts +92 -43
  48. package/css/flicking.css +0 -28
  49. package/declaration/camera/BoundCamera.d.ts +0 -9
  50. package/declaration/camera/CircularCamera.d.ts +0 -37
  51. package/declaration/camera/LinearCamera.d.ts +0 -5
  52. package/dist/flicking-inline.css +0 -2
  53. package/dist/flicking-inline.css.map +0 -1
  54. package/dist/flicking.css +0 -2
  55. package/dist/flicking.css.map +0 -1
  56. package/src/camera/CircularCamera.ts +0 -268
  57. package/src/camera/LinearCamera.ts +0 -35
@@ -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, toArray } 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,21 +22,24 @@ 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;
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
  /**
@@ -72,7 +77,23 @@ abstract class Camera {
72
77
  * @default 0
73
78
  * @readonly
74
79
  */
75
- 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; }
76
97
  /**
77
98
  * A range that Camera's {@link Camera#position position} can reach
78
99
  * @ko Camera의 {@link Camera#position position}이 도달 가능한 범위
@@ -118,7 +139,7 @@ abstract class Camera {
118
139
  * @type {ControlParams}
119
140
  * @readonly
120
141
  */
121
- 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 }; }
122
143
  /**
123
144
  * A Boolean value indicating whether Camera's over the minimum or maximum position reachable
124
145
  * @ko 현재 카메라가 도달 가능한 범위의 최소 혹은 최대점을 넘어섰는지를 나타냅니다
@@ -210,51 +231,33 @@ abstract class Camera {
210
231
  }
211
232
 
212
233
  /** */
213
- public constructor({
234
+ public constructor(flicking: Flicking, {
214
235
  align = ALIGN.CENTER
215
236
  }: Partial<CameraOptions> = {}) {
216
- this._flicking = null;
237
+ this._flicking = flicking;
217
238
  this._resetInternalValues();
218
239
 
219
240
  // Options
220
241
  this._align = align;
221
242
  }
222
243
 
223
- /**
224
- * Update {@link Camera#range range} of Camera
225
- * @ko Camera의 {@link Camera#range range}를 업데이트합니다
226
- * @method
227
- * @abstract
228
- * @memberof Camera
229
- * @instance
230
- * @name updateRange
231
- * @chainable
232
- * @throws {FlickingError}
233
- * {@link ERROR_CODE NOT_ATTACHED_TO_FLICKING} When {@link Camera#init init} is not called before
234
- * <ko>{@link ERROR_CODE NOT_ATTACHED_TO_FLICKING} {@link Camera#init init}이 이전에 호출되지 않은 경우</ko>
235
- * @return {this}
236
- */
237
- public abstract updateRange(): this;
238
-
239
244
  /**
240
245
  * Initialize Camera
241
246
  * @ko Camera를 초기화합니다
242
- * @param {Flicking} flicking An instance of {@link Flicking}<ko>Flicking의 인스턴스</ko>
243
- * @chainable
244
247
  * @throws {FlickingError}
245
248
  * {@link ERROR_CODE VAL_MUST_NOT_NULL} If the camera element(`.flicking-camera`) does not exist inside viewport element
246
249
  * <ko>{@link ERROR_CODE VAL_MUST_NOT_NULL} 뷰포트 엘리먼트 내부에 카메라 엘리먼트(`.flicking-camera`)가 존재하지 않을 경우</ko>
247
250
  * @return {this}
248
251
  */
249
- public init(flicking: Flicking): this {
250
- this._flicking = flicking;
251
-
252
- const viewportEl = flicking.viewport.element;
252
+ public init(): this {
253
+ const viewportEl = this._flicking.viewport.element;
253
254
 
254
255
  checkExistence(viewportEl.firstElementChild, "First element child of the viewport element");
255
256
  this._el = viewportEl.firstElementChild as HTMLElement;
256
257
  this._checkTranslateSupport();
257
258
 
259
+ this._updateMode();
260
+
258
261
  return this;
259
262
  }
260
263
 
@@ -264,7 +267,6 @@ abstract class Camera {
264
267
  * @return {void}
265
268
  */
266
269
  public destroy(): this {
267
- this._flicking = null;
268
270
  this._resetInternalValues();
269
271
  return this;
270
272
  }
@@ -279,13 +281,22 @@ abstract class Camera {
279
281
  * @return {this}
280
282
  */
281
283
  public lookAt(pos: number): void {
284
+ const flicking = getFlickingAttached(this._flicking);
282
285
  const prevPos = this._position;
283
286
 
284
287
  this._position = pos;
288
+ const toggled = this._togglePanels(prevPos, pos);
285
289
  this._refreshVisiblePanels();
286
290
  this._checkNeedPanel();
287
291
  this._checkReachEnd(prevPos, pos);
288
- this.applyTransform();
292
+
293
+ if (toggled) {
294
+ void flicking.renderer.render().then(() => {
295
+ this.updateOffset();
296
+ });
297
+ } else {
298
+ this.applyTransform();
299
+ }
289
300
  }
290
301
 
291
302
  /**
@@ -297,7 +308,19 @@ abstract class Camera {
297
308
  * @return {AnchorPoint | null} The previous {@link AnchorPoint}<ko>이전 {@link AnchorPoint}</ko>
298
309
  */
299
310
  public getPrevAnchor(anchor: AnchorPoint): AnchorPoint | null {
300
- return this._anchors[anchor.index - 1] || null;
311
+ if (!this._circularEnabled || anchor.index !== 0) {
312
+ return this._anchors[anchor.index - 1] || null;
313
+ } else {
314
+ const anchors = this._anchors;
315
+ const rangeDiff = this.rangeDiff;
316
+ const lastAnchor = anchors[anchors.length - 1];
317
+
318
+ return new AnchorPoint({
319
+ index: lastAnchor.index,
320
+ position: lastAnchor.position - rangeDiff,
321
+ panel: lastAnchor.panel
322
+ });
323
+ }
301
324
  }
302
325
 
303
326
  /**
@@ -309,7 +332,20 @@ abstract class Camera {
309
332
  * @return {AnchorPoint | null} The next {@link AnchorPoint}<ko>다음 {@link AnchorPoint}</ko>
310
333
  */
311
334
  public getNextAnchor(anchor: AnchorPoint): AnchorPoint | null {
312
- return this._anchors[anchor.index + 1] || null;
335
+ const anchors = this._anchors;
336
+
337
+ if (!this._circularEnabled || anchor.index !== anchors.length - 1) {
338
+ return anchors[anchor.index + 1] || null;
339
+ } else {
340
+ const rangeDiff = this.rangeDiff;
341
+ const firstAnchor = anchors[0];
342
+
343
+ return new AnchorPoint({
344
+ index: firstAnchor.index,
345
+ position: firstAnchor.position + rangeDiff,
346
+ panel: firstAnchor.panel
347
+ });
348
+ }
313
349
  }
314
350
 
315
351
  /**
@@ -335,16 +371,7 @@ abstract class Camera {
335
371
  * @return {AnchorPoint | null} The {@link AnchorPoint} that includes the given position<ko>해당 좌표를 포함하는 {@link AnchorPoint}</ko>
336
372
  */
337
373
  public findAnchorIncludePosition(position: number): AnchorPoint | null {
338
- const anchors = this._anchors;
339
- const anchorsIncludingPosition = anchors.filter(anchor => anchor.panel.includePosition(position, true));
340
-
341
- return anchorsIncludingPosition.reduce((nearest: AnchorPoint | null, anchor) => {
342
- if (!nearest) return anchor;
343
-
344
- return Math.abs(nearest.position - position) < Math.abs(anchor.position - position)
345
- ? nearest
346
- : anchor;
347
- }, null);
374
+ return this._mode.findAnchorIncludePosition(position);
348
375
  }
349
376
 
350
377
  /**
@@ -396,8 +423,7 @@ abstract class Camera {
396
423
  * @return {number} A clamped position<ko>범위 제한된 좌표</ko>
397
424
  */
398
425
  public clampToReachablePosition(position: number): number {
399
- const range = this._range;
400
- return clamp(position, range.min, range.max);
426
+ return this._mode.clampToReachablePosition(position);
401
427
  }
402
428
 
403
429
  /**
@@ -407,13 +433,7 @@ abstract class Camera {
407
433
  * @return {boolean} Whether the panel's inside Camera's range<ko>도달 가능한 범위 내에 해당 패널이 존재하는지 여부</ko>
408
434
  */
409
435
  public canReach(panel: Panel): boolean {
410
- const range = this._range;
411
-
412
- if (panel.removed) return false;
413
-
414
- const panelPos = panel.position;
415
-
416
- return panelPos >= range.min && panelPos <= range.max;
436
+ return this._mode.canReach(panel);
417
437
  }
418
438
 
419
439
  /**
@@ -423,9 +443,36 @@ abstract class Camera {
423
443
  * @return Whether the panel element is visible at the current position<ko>현재 위치에서 해당 패널 엘리먼트가 보이는지 여부</ko>
424
444
  */
425
445
  public canSee(panel: Panel): boolean {
426
- const visibleRange = this.visibleRange;
427
- // Should not include margin, as we don't declare what the margin is visible as what the panel is visible.
428
- return panel.isVisibleOnRange(visibleRange.min, visibleRange.max);
446
+ return this._mode.canSee(panel);
447
+ }
448
+
449
+ /**
450
+ * Update {@link Camera#range range} of Camera
451
+ * @ko Camera의 {@link Camera#range range}를 업데이트합니다
452
+ * @method
453
+ * @abstract
454
+ * @memberof Camera
455
+ * @instance
456
+ * @name updateRange
457
+ * @chainable
458
+ * @throws {FlickingError}
459
+ * {@link ERROR_CODE NOT_ATTACHED_TO_FLICKING} When {@link Camera#init init} is not called before
460
+ * <ko>{@link ERROR_CODE NOT_ATTACHED_TO_FLICKING} {@link Camera#init init}이 이전에 호출되지 않은 경우</ko>
461
+ * @return {this}
462
+ */
463
+ public updateRange() {
464
+ const flicking = getFlickingAttached(this._flicking);
465
+ const renderer = flicking.renderer;
466
+ const panels = renderer.panels;
467
+
468
+ this._updateMode();
469
+ this._range = this._mode.getRange();
470
+
471
+ if (this._circularEnabled) {
472
+ panels.forEach(panel => panel.updateCircularToggleDirection());
473
+ }
474
+
475
+ return this;
429
476
  }
430
477
 
431
478
  /**
@@ -456,14 +503,7 @@ abstract class Camera {
456
503
  * @return {this}
457
504
  */
458
505
  public updateAnchors(): this {
459
- const flicking = getFlickingAttached(this._flicking);
460
- const panels = flicking.renderer.panels;
461
-
462
- this._anchors = panels.map((panel, index) => new AnchorPoint({
463
- index,
464
- position: panel.position,
465
- panel
466
- }));
506
+ this._anchors = this._mode.getAnchors();
467
507
 
468
508
  return this;
469
509
  }
@@ -503,6 +543,8 @@ abstract class Camera {
503
543
  .filter(panel => panel.position + panel.offset < position)
504
544
  .reduce((offset, panel) => offset + panel.sizeIncludingMargin, 0);
505
545
 
546
+ this._circularOffset = this._mode.getCircularOffset();
547
+
506
548
  this.applyTransform();
507
549
 
508
550
  return this;
@@ -522,14 +564,16 @@ abstract class Camera {
522
564
  /**
523
565
  * Apply "transform" style with the current position to camera element
524
566
  * @ko 현재 위치를 기준으로한 transform 스타일을 카메라 엘리먼트에 적용합니다.
525
- * @chainable
526
567
  * @return {this}
527
568
  */
528
569
  public applyTransform(): this {
529
570
  const el = this._el;
530
571
  const flicking = getFlickingAttached(this._flicking);
572
+ const renderer = flicking.renderer;
573
+
574
+ if (renderer.rendering) return this;
531
575
 
532
- const actualPosition = this._position - this._alignPos - this._offset;
576
+ const actualPosition = this._position - this._alignPos - this._offset + this._circularOffset;
533
577
 
534
578
  el.style[this._transform] = flicking.horizontal
535
579
  ? `translate(${-actualPosition}px)`
@@ -538,17 +582,19 @@ abstract class Camera {
538
582
  return this;
539
583
  }
540
584
 
541
- protected _resetInternalValues() {
585
+ private _resetInternalValues() {
542
586
  this._position = 0;
543
587
  this._alignPos = 0;
544
588
  this._offset = 0;
589
+ this._circularOffset = 0;
590
+ this._circularEnabled = false;
545
591
  this._range = { min: 0, max: 0 };
546
592
  this._visiblePanels = [];
547
593
  this._anchors = [];
548
594
  this._needPanelTriggered = { prev: false, next: false };
549
595
  }
550
596
 
551
- protected _refreshVisiblePanels() {
597
+ private _refreshVisiblePanels() {
552
598
  const flicking = getFlickingAttached(this._flicking);
553
599
  const panels = flicking.renderer.panels;
554
600
 
@@ -570,7 +616,7 @@ abstract class Camera {
570
616
  }
571
617
  }
572
618
 
573
- protected _checkNeedPanel(): void {
619
+ private _checkNeedPanel(): void {
574
620
  const needPanelTriggered = this._needPanelTriggered;
575
621
 
576
622
  if (needPanelTriggered.prev && needPanelTriggered.next) return;
@@ -621,7 +667,7 @@ abstract class Camera {
621
667
  }
622
668
  }
623
669
 
624
- protected _checkReachEnd(prevPos: number, newPos: number): void {
670
+ private _checkReachEnd(prevPos: number, newPos: number): void {
625
671
  const flicking = getFlickingAttached(this._flicking);
626
672
  const range = this._range;
627
673
 
@@ -637,7 +683,7 @@ abstract class Camera {
637
683
  }));
638
684
  }
639
685
 
640
- protected _checkTranslateSupport = () => {
686
+ private _checkTranslateSupport = () => {
641
687
  const transforms = ["webkitTransform", "msTransform", "MozTransform", "OTransform", "transform"];
642
688
 
643
689
  const supportedStyle = document.documentElement.style;
@@ -654,6 +700,41 @@ abstract class Camera {
654
700
 
655
701
  this._transform = transformName;
656
702
  };
703
+
704
+ private _updateMode() {
705
+ const flicking = getFlickingAttached(this._flicking);
706
+
707
+ if (flicking.circular) {
708
+ const circularMode = new CircularCameraMode(flicking);
709
+ const canSetCircularMode = circularMode.checkAvailability();
710
+
711
+ if (canSetCircularMode) {
712
+ this._mode = circularMode;
713
+ } else {
714
+ const fallbackMode = flicking.circularFallback;
715
+
716
+ this._mode = fallbackMode === CIRCULAR_FALLBACK.BOUND
717
+ ? new BoundCameraMode(flicking)
718
+ : new LinearCameraMode(flicking);
719
+ }
720
+
721
+ this._circularEnabled = canSetCircularMode;
722
+ } else {
723
+ this._mode = flicking.bound
724
+ ? new BoundCameraMode(flicking)
725
+ : new LinearCameraMode(flicking);
726
+ }
727
+ }
728
+
729
+ private _togglePanels(prevPos: number, pos: number): boolean {
730
+ if (pos === prevPos) return false;
731
+
732
+ const flicking = getFlickingAttached(this._flicking);
733
+ const panels = flicking.renderer.panels;
734
+ const toggled = panels.map(panel => panel.toggle(prevPos, pos));
735
+
736
+ return toggled.some(isToggled => isToggled);
737
+ }
657
738
  }
658
739
 
659
740
  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);
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);
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;
@@ -0,0 +1,77 @@
1
+ /*
2
+ * Copyright (c) 2015 NAVER Corp.
3
+ * egjs projects are licensed under the MIT license
4
+ */
5
+ import Flicking from "../../Flicking";
6
+ import Panel from "../../core/panel/Panel";
7
+ import AnchorPoint from "../../core/AnchorPoint";
8
+ import { clamp } from "../../utils";
9
+
10
+ /**
11
+ * A mode of camera
12
+ */
13
+ abstract class CameraMode {
14
+ protected _flicking: Flicking;
15
+
16
+ /** */
17
+ public constructor(flicking: Flicking) {
18
+ this._flicking = flicking;
19
+ }
20
+
21
+ public abstract checkAvailability(): boolean;
22
+ public abstract getRange(): { min: number; max: number };
23
+
24
+ public getAnchors(): AnchorPoint[] {
25
+ const panels = this._flicking.renderer.panels;
26
+
27
+ return panels.map((panel, index) => new AnchorPoint({
28
+ index,
29
+ position: panel.position,
30
+ panel
31
+ }));
32
+ }
33
+
34
+ public findAnchorIncludePosition(position: number): AnchorPoint | null {
35
+ const anchors = this._flicking.camera.anchorPoints;
36
+ const anchorsIncludingPosition = anchors.filter(anchor => anchor.panel.includePosition(position, true));
37
+
38
+ return anchorsIncludingPosition.reduce((nearest: AnchorPoint | null, anchor) => {
39
+ if (!nearest) return anchor;
40
+
41
+ return Math.abs(nearest.position - position) < Math.abs(anchor.position - position)
42
+ ? nearest
43
+ : anchor;
44
+ }, null);
45
+ }
46
+
47
+ public clampToReachablePosition(position: number): number {
48
+ const camera = this._flicking.camera;
49
+ const range = camera.range;
50
+
51
+ return clamp(position, range.min, range.max);
52
+ }
53
+
54
+ public getCircularOffset(): number {
55
+ return 0;
56
+ }
57
+
58
+ public canReach(panel: Panel): boolean {
59
+ const camera = this._flicking.camera;
60
+ const range = camera.range;
61
+
62
+ if (panel.removed) return false;
63
+
64
+ const panelPos = panel.position;
65
+
66
+ return panelPos >= range.min && panelPos <= range.max;
67
+ }
68
+
69
+ public canSee(panel: Panel): boolean {
70
+ const camera = this._flicking.camera;
71
+ const visibleRange = camera.visibleRange;
72
+ // Should not include margin, as we don't declare what the margin is visible as what the panel is visible.
73
+ return panel.isVisibleOnRange(visibleRange.min, visibleRange.max);
74
+ }
75
+ }
76
+
77
+ export default CameraMode;