• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

naver / egjs-flicking / 10557177632

26 Aug 2024 09:22AM UTC coverage: 38.327% (-44.5%) from 82.855%
10557177632

Pull #886

github

daybrush
fix: recalculate camera offset
Pull Request #886: fix: recalculate camera offset

2039 of 7372 branches covered (27.66%)

Branch coverage included in aggregate %.

11 of 29 new or added lines in 2 files covered. (37.93%)

5575 existing lines in 46 files now uncovered.

5099 of 11252 relevant lines covered (45.32%)

10.91 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

55.98
/src/camera/mode/CircularCameraMode.ts
1
/*
1✔
2
 * Copyright (c) 2015 NAVER Corp.
1✔
3
 * egjs projects are licensed under the MIT license
1✔
4
 */
1!
5
import Panel from "../../core/panel/Panel";
6
import AnchorPoint from "../../core/AnchorPoint";
5!
7
import { DIRECTION } from "../../const/external";
6✔
8
import { circulatePosition } from "../../utils";
5✔
9

1✔
10
import CameraMode from "./CameraMode";
6!
11

12
/**
1✔
13
 * A {@link Camera} mode that connects the last panel and the first panel, enabling continuous loop
1✔
14
 * @ko 첫번째 패널과 마지막 패널이 이어진 상태로, 무한히 회전할 수 있는 종류의 {@link Camera} 모드
1!
15
 */
16
class CircularCameraMode extends CameraMode {
5✔
17
  public checkAvailability(): boolean {
6✔
18
    const flicking = this._flicking;
4!
19
    const renderer = flicking.renderer;
2✔
20
    const panels = renderer.panels;
3✔
21

1✔
22
    if (panels.length <= 0) {
3✔
23
      return false;
2✔
24
    }
1✔
25

26
    const firstPanel = panels[0];
1✔
27
    const lastPanel = panels[panels.length - 1];
1✔
28
    const firstPanelPrev = firstPanel.range.min - firstPanel.margin.prev;
1✔
29
    const lastPanelNext = lastPanel.range.max + lastPanel.margin.next;
2✔
30

1✔
31
    const visibleSize = flicking.camera.size;
1✔
32
    const panelSizeSum = lastPanelNext - firstPanelPrev;
1!
33

34
    const canSetCircularMode = panels
2✔
35
      .every(panel => panelSizeSum - panel.size >= visibleSize);
3✔
36

37
    return canSetCircularMode;
1✔
38
  }
×
39

40
  public getRange(): { min: number; max: number } {
5✔
41
    const flicking = this._flicking;
1✔
42
    const panels = flicking.renderer.panels;
1✔
43

44
    if (panels.length <= 0) {
1!
UNCOV
45
      return { min: 0, max: 0 };
×
46
    }
47

48
    const firstPanel = panels[0];
1✔
49
    const lastPanel = panels[panels.length - 1];
1✔
50
    const firstPanelPrev = firstPanel.range.min - firstPanel.margin.prev;
1✔
51
    const lastPanelNext = lastPanel.range.max + lastPanel.margin.next;
2✔
52

53
    return { min: firstPanelPrev, max: lastPanelNext };
1✔
54
  }
×
55

56
  public getAnchors(): AnchorPoint[] {
5✔
57
    const flicking = this._flicking;
1✔
58
    const panels = flicking.renderer.panels;
1✔
59

60
    return panels.map((panel, index) => new AnchorPoint({
3✔
61
      index,
62
      position: panel.position,
63
      panel
1✔
64
    }));
65
  }
66

67
  public findNearestAnchor(position: number): AnchorPoint | null {
5✔
68
    const camera = this._flicking.camera;
1✔
69
    const anchors = camera.anchorPoints;
1✔
70

71
    if (anchors.length <= 0) return null;
1!
72

1✔
73
    const camRange = camera.range;
1✔
74
    let minDist = Infinity;
1✔
75
    let minDistIndex = -1;
1!
76
    for (let anchorIdx = 0; anchorIdx < anchors.length; anchorIdx++) {
1✔
77
      const anchor = anchors[anchorIdx];
3✔
78
      const dist = Math.min(
3✔
79
        Math.abs(anchor.position - position),
80
        Math.abs(anchor.position - camRange.min + camRange.max - position),
81
        Math.abs(position - camRange.min + camRange.max - anchor.position)
82
      );
83

×
84
      if (dist < minDist) {
3✔
85
        minDist = dist;
1✔
86
        minDistIndex = anchorIdx;
1✔
87
      }
88
    }
89

90
    // Return last anchor
91
    return anchors[minDistIndex];
2✔
92
  }
93

94
  public findAnchorIncludePosition(position: number): AnchorPoint | null {
5✔
UNCOV
95
    const camera = this._flicking.camera;
×
UNCOV
96
    const range = camera.range;
×
UNCOV
97
    const anchors = camera.anchorPoints;
×
UNCOV
98
    const rangeDiff = camera.rangeDiff;
×
UNCOV
99
    const anchorCount = anchors.length;
×
UNCOV
100
    const positionInRange = circulatePosition(position, range.min, range.max);
×
101

102
    let anchorInRange: AnchorPoint | null = super.findAnchorIncludePosition(positionInRange);
103

104
    if (anchorCount > 0 && (position === range.min || position === range.max)) {
×
105
      const possibleAnchors = [
106
        anchorInRange,
107
        new AnchorPoint({
108
          index: 0,
109
          position: anchors[0].position + rangeDiff,
110
          panel: anchors[0].panel
111
        }),
112
        new AnchorPoint({
113
          index: anchorCount - 1,
114
          position: anchors[anchorCount - 1].position - rangeDiff,
×
115
          panel: anchors[anchorCount - 1].panel
116
        })
×
117
      ].filter(anchor => !!anchor) as AnchorPoint[];
118

119
      anchorInRange = possibleAnchors.reduce((nearest: AnchorPoint | null, anchor) => {
120
        if (!nearest) return anchor;
×
121

×
122
        return Math.abs(nearest.position - position) < Math.abs(anchor.position - position)
×
123
          ? nearest
×
124
          : anchor;
125
      }, null);
126
    }
127

128
    if (!anchorInRange) return null;
×
129

130
    if (position < range.min) {
×
UNCOV
131
      const loopCount = -Math.floor((range.min - position) / rangeDiff) - 1;
×
132

UNCOV
133
      return new AnchorPoint({
×
134
        index: anchorInRange.index,
135
        position: anchorInRange.position + rangeDiff * loopCount,
136
        panel: anchorInRange.panel
137
      });
138
    } else if (position > range.max) {
×
UNCOV
139
      const loopCount = Math.floor((position - range.max) / rangeDiff) + 1;
×
140

141
      return new AnchorPoint({
1✔
142
        index: anchorInRange.index,
143
        position: anchorInRange.position + rangeDiff * loopCount,
144
        panel: anchorInRange.panel
×
145
      });
146
    }
147

UNCOV
148
    return anchorInRange;
×
149
  }
150

151
  public getCircularOffset(): number {
6✔
152
    const flicking = this._flicking;
3✔
153
    const camera = flicking.camera;
3✔
154

155
    if (!camera.circularEnabled) return 0;
4!
156

×
157
    const toggled = flicking.panels.filter(panel => panel.toggled);
9✔
158
    const toggledPrev = toggled.filter(panel => panel.toggleDirection === DIRECTION.PREV);
3✔
159
    const toggledNext = toggled.filter(panel => panel.toggleDirection === DIRECTION.NEXT);
3✔
160

161
    return this._calcPanelAreaSum(toggledPrev) - this._calcPanelAreaSum(toggledNext);
4✔
162
  }
163

164
  public clampToReachablePosition(position: number): number {
5✔
165
    // Basically all position is reachable for circular camera
UNCOV
166
    return position;
×
167
  }
168

×
169
  public canReach(panel: Panel): boolean {
5!
170
    if (panel.removed) return false;
1!
171

×
172
    // Always reachable on circular mode
×
173
    return true;
1✔
174
  }
175

176
  public canSee(panel: Panel): boolean {
6✔
177
    const camera = this._flicking.camera;
3✔
178
    const range = camera.range;
3✔
179
    const rangeDiff = camera.rangeDiff;
4✔
180
    const visibleRange = camera.visibleRange;
3✔
181
    const visibleInCurrentRange = super.canSee(panel);
4✔
182

183
    // Check looped visible area for circular case
184
    if (visibleRange.min < range.min) {
3!
185
      return visibleInCurrentRange || panel.isVisibleOnRange(visibleRange.min + rangeDiff, visibleRange.max + rangeDiff);
×
186
    } else if (visibleRange.max > range.max) {
3!
187
      return visibleInCurrentRange || panel.isVisibleOnRange(visibleRange.min - rangeDiff, visibleRange.max - rangeDiff);
×
188
    }
189

190
    return visibleInCurrentRange;
3✔
191
  }
192

193
  private _calcPanelAreaSum(panels: Panel[]) {
5✔
194
    return panels.reduce((sum: number, panel: Panel) => sum + panel.sizeIncludingMargin, 0);
6✔
195
  }
196
}
5✔
197

198
export default CircularCameraMode;
5✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc