@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.
- package/TODO.md +3 -0
- package/declaration/Flicking.d.ts +15 -2
- package/declaration/camera/Camera.d.ts +28 -26
- package/declaration/camera/index.d.ts +2 -4
- package/declaration/camera/mode/BoundCameraMode.d.ts +13 -0
- package/declaration/camera/mode/CameraMode.d.ts +19 -0
- package/declaration/camera/mode/CircularCameraMode.d.ts +18 -0
- package/declaration/camera/mode/LinearCameraMode.d.ts +9 -0
- package/declaration/camera/mode/index.d.ts +6 -0
- package/declaration/const/external.d.ts +4 -0
- package/declaration/control/StrictControl.d.ts +1 -0
- package/declaration/core/AutoResizer.d.ts +3 -0
- package/declaration/core/ResizeWatcher.d.ts +33 -0
- package/declaration/renderer/Renderer.d.ts +13 -0
- package/declaration/type/external.d.ts +1 -3
- package/{css → dist/css}/flicking-inline.css +20 -13
- package/dist/css/flicking-inline.min.css +1 -0
- package/dist/css/flicking.css +44 -0
- package/dist/css/flicking.min.css +1 -0
- package/dist/flicking.esm.js +1491 -1251
- package/dist/flicking.esm.js.map +1 -1
- package/dist/flicking.js +1494 -1253
- package/dist/flicking.js.map +1 -1
- package/dist/flicking.min.js +2 -2
- package/dist/flicking.min.js.map +1 -1
- package/dist/flicking.pkgd.js +1466 -1225
- package/dist/flicking.pkgd.js.map +1 -1
- package/dist/flicking.pkgd.min.js +2 -2
- package/dist/flicking.pkgd.min.js.map +1 -1
- package/package.json +17 -7
- package/sass/flicking-inline.sass +30 -0
- package/sass/flicking.sass +23 -0
- package/src/Flicking.ts +127 -35
- package/src/camera/Camera.ts +162 -81
- package/src/camera/index.ts +3 -7
- package/src/camera/{BoundCamera.ts → mode/BoundCameraMode.ts} +46 -43
- package/src/camera/mode/CameraMode.ts +77 -0
- package/src/camera/mode/CircularCameraMode.ts +171 -0
- package/src/camera/mode/LinearCameraMode.ts +23 -0
- package/src/camera/mode/index.ts +14 -0
- package/src/cfc/sync.ts +29 -23
- package/src/cfc/withFlickingMethods.ts +3 -2
- package/src/const/external.ts +12 -0
- package/src/control/StrictControl.ts +10 -0
- package/src/core/AutoResizer.ts +33 -0
- package/src/core/ResizeWatcher.ts +133 -0
- package/src/renderer/Renderer.ts +92 -43
- package/css/flicking.css +0 -28
- package/declaration/camera/BoundCamera.d.ts +0 -9
- package/declaration/camera/CircularCamera.d.ts +0 -37
- package/declaration/camera/LinearCamera.d.ts +0 -5
- package/dist/flicking-inline.css +0 -2
- package/dist/flicking-inline.css.map +0 -1
- package/dist/flicking.css +0 -2
- package/dist/flicking.css.map +0 -1
- package/src/camera/CircularCamera.ts +0 -268
- package/src/camera/LinearCamera.ts +0 -35
package/src/camera/Camera.ts
CHANGED
|
@@ -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,
|
|
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
|
-
|
|
25
|
+
class Camera {
|
|
24
26
|
// Options
|
|
25
|
-
|
|
27
|
+
private _align: FlickingOptions["align"];
|
|
26
28
|
|
|
27
29
|
// Internal states
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
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:
|
|
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 =
|
|
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(
|
|
250
|
-
this._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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
427
|
-
|
|
428
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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;
|
package/src/camera/index.ts
CHANGED
|
@@ -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
|
|
6
|
-
import
|
|
7
|
-
import {
|
|
5
|
+
import AnchorPoint from "../../core/AnchorPoint";
|
|
6
|
+
import Panel from "../../core/panel/Panel";
|
|
7
|
+
import { parseAlign } from "../../utils";
|
|
8
8
|
|
|
9
|
-
import
|
|
9
|
+
import CameraMode from "./CameraMode";
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
const
|
|
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 =
|
|
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
|
-
|
|
35
|
-
return this;
|
|
41
|
+
return { min: 0, max: 0 };
|
|
36
42
|
}
|
|
37
43
|
|
|
38
|
-
const viewportSize =
|
|
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
|
-
|
|
54
|
+
return { min: firstPos, max: lastPos };
|
|
49
55
|
} else {
|
|
50
|
-
const 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
|
-
|
|
63
|
+
return { min: pos, max: pos };
|
|
58
64
|
}
|
|
59
|
-
|
|
60
|
-
return this;
|
|
61
65
|
}
|
|
62
66
|
|
|
63
|
-
public
|
|
64
|
-
const 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
|
-
|
|
69
|
-
return this;
|
|
73
|
+
return [];
|
|
70
74
|
}
|
|
71
75
|
|
|
72
|
-
const range =
|
|
73
|
-
const reachablePanels = panels.filter(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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
136
|
-
const
|
|
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
|
|
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;
|