• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (c) 2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16import { Dispatch, getStore, OhCombinedState } from '../../redux/store';
17import { Action } from '../../redux/actions/Action';
18import { EventBus } from '../../worker/eventbus/EventBus';
19import { EventBusManager } from '../../worker/eventbus/EventBusManager';
20import { CameraId } from '../../setting/settingitem/CameraId';
21
22let SHOW_FOLD_CANVAS: number = 0
23let SHOW_NOT_TAKE_VIDEO_CANVAS: number = 1
24let SHOW_TAKING_VIDEO_CANVAS: number = 2
25
26class StateStruct {
27  mode: string = 'PHOTO';
28  videoState: string = 'beforeTakeVideo';
29  cameraPosition: CameraId = CameraId.BACK;
30  zoomRatio: number = 1;
31  isShowZoomText: boolean = false;
32  showZoomLabelValue: boolean = true;
33  minZoomRatio: number = 1;
34  maxZoomRatio: number = 6;
35}
36
37
38class ZoomViewDispatcher {
39  public setDispatch(dispatch: Dispatch) {
40    this.mDispatch = dispatch;
41  }
42
43  public updateZoomRatio(zoomRatio: number): void {
44    this.mDispatch(Action.changeZoomRatio(zoomRatio));
45  }
46
47  public updateShowZoomFlag(flag: boolean): void {
48    this.mDispatch(Action.updateShowZoomTextFlag(flag));
49  }
50
51  public updateShowZoomLabelValue(flag: boolean): void {
52    this.mDispatch(Action.updateShowZoomLabelValue(flag));
53  }
54
55  private mDispatch: Dispatch = (data) => data;
56}
57
58class ZoomRatioStruct {
59  zoomRatio: number = 0;
60}
61
62class VideoStateStruct {
63  videoState: string = '';
64}
65
66@Component
67export struct ZoomViewLand {
68  @State state: StateStruct = new StateStruct()
69  @State @Watch('onZoomRatioRefresh') zoomRatio: number = 0
70  @State @Watch('onZoomRatioRefresh') showZoomLabelValue: boolean = true
71  @State @Watch('onZoomRatioRefresh') isShowZoomText: boolean = false
72  @State @Watch('onZoomRatioRefresh') curZoomRatio: number = 0
73  @State offsetY: number = 0
74  @State triggerRebuildNum: number = 0
75  private appEventBus: EventBus = EventBusManager.getInstance().getEventBus()
76  private mAction: ZoomViewDispatcher = new ZoomViewDispatcher();
77  private canvasWidth: number = 82
78  private notTakeVideoExtCanvasHeight: number = 360
79  private takingVideoExtCanvasHeight: number = 196
80  private foldCanvasHeight: number = 94
81  private touchedOffsetY: number = this.takingVideoExtCanvasHeight / 2
82  private startOffsetY: number = 0
83  private canvasSettings: RenderingContextSettings = new RenderingContextSettings(true)
84  private notTakeVideoExtCanvasCxt: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.canvasSettings)
85  private takingVideoExtCanvasCxt: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.canvasSettings)
86  private foldCanvasCxt: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.canvasSettings)
87  private notTakeVideoExtOffCanvasCxt: OffscreenCanvasRenderingContext2D = new OffscreenCanvasRenderingContext2D(
88    this.canvasWidth, this.notTakeVideoExtCanvasHeight, this.canvasSettings)
89  private takingVideoExtOffCanvasCxt: OffscreenCanvasRenderingContext2D = new OffscreenCanvasRenderingContext2D(
90    this.canvasWidth, this.notTakeVideoExtCanvasHeight, this.canvasSettings)
91  private foldOffCanvasCxt: OffscreenCanvasRenderingContext2D = new OffscreenCanvasRenderingContext2D(
92    this.canvasWidth, this.foldCanvasHeight, this.canvasSettings)
93  private lpgTimer: number = 0
94  private pgTimer: number = 0
95  private lpgExp: boolean = false
96  private pgExp: boolean = false
97  private zoomTimer: number = 0
98  private baseZoomRatio: number = 1
99  private mainDotRadius: number = 1.5
100  private secDotRadius: number = 0.75
101  private centerDotRadius: number = 2.5
102  private dotSpacing: number = 4
103  private refreshSwitchCanvas: number = -1
104
105  aboutToAppear(): void {
106    getStore().subscribe((state: OhCombinedState) => {
107      this.state = {
108        mode: state.modeReducer.mode,
109        videoState: state.recordReducer.videoState,
110        cameraPosition: state.cameraReducer.cameraPosition,
111        zoomRatio: state.zoomReducer.zoomRatio,
112        isShowZoomText: state.zoomReducer.isShowZoomText,
113        showZoomLabelValue: state.zoomReducer.showZoomLabelValue,
114        minZoomRatio: state.zoomReducer.minZoomRatio,
115        maxZoomRatio: state.zoomReducer.maxZoomRatio
116      };
117    }, (dispatch: Dispatch) => {
118      this.mAction.setDispatch(dispatch);
119    });
120
121    this.appEventBus.on(Action.ACTION_CHANGE_ZOOM_RATIO, (data: ZoomRatioStruct) => this.updateZoomOffset(data))
122    this.appEventBus.on(Action.ACTION_UPDATE_VIDEO_STATE, (data: VideoStateStruct) => this.updateZoomState(data))
123  }
124
125  aboutToDisappear(): void {
126    this.appEventBus.off(Action.ACTION_CHANGE_ZOOM_RATIO, (data: ZoomRatioStruct) => this.updateZoomOffset(data))
127    this.appEventBus.off(Action.ACTION_UPDATE_VIDEO_STATE, (data: VideoStateStruct) => this.updateZoomState(data))
128  }
129
130  build() {
131    Stack({ alignContent: Alignment.Start }) {
132      Stack({ alignContent: Alignment.Top })
133        .width(this.triggerRebuildNum)
134        .height(this.offsetY + this.touchedOffsetY + this.zoomRatio)
135        .visibility(Visibility.None)
136      if (this.getCurrentCanvasType() === SHOW_NOT_TAKE_VIDEO_CANVAS) {
137        Canvas(this.notTakeVideoExtCanvasCxt)
138          .width(this.canvasWidth)
139          .height(this.notTakeVideoExtCanvasHeight)
140          .onReady(() => this.canvasInit(SHOW_NOT_TAKE_VIDEO_CANVAS))
141          .gesture(
142            GestureGroup(
143              GestureMode.Parallel,
144              PanGesture({ fingers: 1, distance: 1, direction: PanDirection.Vertical })
145                .onActionStart(() => this.pgOnActionStart())
146                .onActionUpdate((event?: GestureEvent) => {
147                  if (event) {
148                    return this.pgOnActionUpdate(event);
149                  }
150                })
151                .onActionEnd(() => this.pgOnActionEnd())))
152          .onTouch((event?: TouchEvent) => {
153            if (event) {
154              return this.mOnTouch(event);
155            }
156          })
157      } else if (this.getCurrentCanvasType() === SHOW_TAKING_VIDEO_CANVAS) {
158        Column() {
159          Image($r('app.media.ic_camera_public_focus_ev_bright_add'))
160            .width(24)
161            .height(24)
162            .fillColor(Color.White)
163            .onTouch((event?: TouchEvent) => this.addTouched(event))
164            .gesture(
165              GestureGroup(
166                GestureMode.Parallel,
167                LongPressGesture({ repeat: true })
168                  .onAction(() => this.addLongOnAction())
169                  .onActionEnd(() => this.addLongOnActionEnd()),
170              )
171            )
172          Canvas(this.takingVideoExtCanvasCxt)
173            .width(this.canvasWidth)
174            .height(this.takingVideoExtCanvasHeight)
175            .onReady(() => this.canvasInit(SHOW_TAKING_VIDEO_CANVAS))
176            .gesture(
177              GestureGroup(
178                GestureMode.Parallel,
179                LongPressGesture({ repeat: true })
180                  .onAction((event?: GestureEvent) => this.takingVideoExtLongPgAction(event))
181                  .onActionEnd(() => this.takingVideoExtLongPgActionEnd()),
182                PanGesture({ fingers: 1, distance: 1, direction: PanDirection.Horizontal })
183                  .onActionStart((event?: GestureEvent) => this.takingVideoExtPgActionStart(event))
184                  .onActionUpdate((event?: GestureEvent) => this.takingVideoExtPgActionUpdate(event))
185                  .onActionEnd((event?: GestureEvent) => this.takingVideoExtPgActionEnd(event))
186              ))
187            .onTouch((event?: TouchEvent) => this.takingVideoExtTouched(event))
188          Image($r('app.media.ic_camera_public_focus_ev_bright_subtract'))
189            .width(24)
190            .height(24)
191            .fillColor(Color.White)
192            .onTouch((event?: TouchEvent) => this.subtractTouched(event))
193            .gesture(
194              GestureGroup(
195                GestureMode.Parallel,
196                LongPressGesture({ repeat: true })
197                  .onAction((event?: GestureEvent) => this.subtractLongOnAction(event))
198                  .onActionEnd(() => this.subtractLongOnActionEnd()),
199              )
200            )
201        }.width('100%').height(this.notTakeVideoExtCanvasHeight).padding({ top: 58, bottom: 58 })
202      } else {
203        Canvas(this.foldCanvasCxt)
204          .width(this.canvasWidth)
205          .height(this.foldCanvasHeight)
206          .onReady(() => this.canvasInit(SHOW_FOLD_CANVAS))
207          .gesture(
208            GestureGroup(
209              GestureMode.Parallel,
210              LongPressGesture({ repeat: true })
211                .onAction(() => this.lpgOnAction())
212                .onActionEnd(() => this.lpgOnActionEnd()),
213              PanGesture({ fingers: 1, distance: 1, direction: PanDirection.Horizontal })
214                .onActionStart(() => this.pgOnActionStart())
215                .onActionUpdate((event?: GestureEvent) => this.pgOnActionUpdate(event))
216                .onActionEnd(() => this.pgOnActionEnd())
217            )
218          )
219      }
220    }.width(82).height('100%')
221  }
222
223  private getCurrentCanvasType(): number {
224    if (this.isShowZoomText && (this.state.videoState === 'beforeTakeVideo'
225      && (this.state.mode === 'PHOTO' || this.state.mode === 'VIDEO'))) {
226      return SHOW_NOT_TAKE_VIDEO_CANVAS
227    } else if (this.state.mode === 'VIDEO'
228      && (this.isShowZoomText || this.state.videoState !== 'beforeTakeVideo')) {
229      return SHOW_TAKING_VIDEO_CANVAS
230    } else {
231      return SHOW_FOLD_CANVAS
232    }
233  }
234
235  private changeZoomRatioOnTakingVideoExt(): void {
236    if (this.touchedOffsetY < this.takingVideoExtCanvasHeight / 2) {
237      this.addZoomRatio()
238    } else if (this.touchedOffsetY > this.takingVideoExtCanvasHeight / 2) {
239      this.subtractZoomRatio()
240    } else {
241      this.triggerRebuildNum = this.triggerRebuildNum + 0.0001
242      this.mAction.updateShowZoomFlag(false)
243    }
244  }
245
246  private addZoomRatio(): void {
247    this.curZoomRatio = this.zoomRatio + 0.1
248    if (this.curZoomRatio > this.state.maxZoomRatio) {
249      this.curZoomRatio = this.state.maxZoomRatio
250    }
251    this.mAction.updateZoomRatio(this.curZoomRatio)
252    this.mAction.updateShowZoomFlag(true)
253    this.triggerRebuildNum = this.triggerRebuildNum + 0.0001
254  }
255
256  private subtractZoomRatio(): void {
257    this.curZoomRatio = this.zoomRatio - 0.1
258    if (this.curZoomRatio < this.state.minZoomRatio) {
259      this.curZoomRatio = this.state.minZoomRatio
260    }
261    this.mAction.updateZoomRatio(this.curZoomRatio)
262    this.mAction.updateShowZoomFlag(true)
263    this.triggerRebuildNum = this.triggerRebuildNum - 0.0001
264  }
265
266  private takingVideoExtTouched(event?: TouchEvent): void {
267    if (!event) {
268      return;
269    }
270    if (event.type === TouchType.Down) {
271      this.touchedOffsetY = event.touches[0].y
272      this.startOffsetY = event.touches[0].y
273      this.changeZoomRatioOnTakingVideoExt()
274    }
275    if (event.type === TouchType.Up) {
276      this.touchedOffsetY = this.takingVideoExtCanvasHeight / 2
277      this.changeZoomRatioOnTakingVideoExt()
278    }
279  }
280
281  private takingVideoExtLongPgAction(event?: GestureEvent): void {
282    if (!event) {
283      return;
284    }
285    this.touchedOffsetY = event.fingerList[0].localY
286    this.changeZoomRatioOnTakingVideoExt()
287  }
288
289  private takingVideoExtLongPgActionEnd(): void {
290    this.touchedOffsetY = this.takingVideoExtCanvasHeight / 2
291    this.changeZoomRatioOnTakingVideoExt()
292  }
293
294  private takingVideoExtPgActionStart(event?: GestureEvent): void {
295    if (!event) {
296      return;
297    }
298    this.touchedOffsetY = this.startOffsetY + event.offsetY
299    this.changeZoomRatioOnTakingVideoExt()
300  }
301
302  private takingVideoExtPgActionUpdate(event?: GestureEvent): void {
303    if (!event) {
304      return;
305    }
306    this.touchedOffsetY = this.startOffsetY + event.offsetY
307    let takingVideoExtMaxOffsetY = this.takingVideoExtCanvasHeight - this.getZoomBtnRadius() - this.secDotRadius
308    let takingVideoExtMinOffsetY = this.getZoomBtnRadius() + this.secDotRadius
309    if (this.touchedOffsetY > takingVideoExtMaxOffsetY) {
310      this.touchedOffsetY = takingVideoExtMaxOffsetY
311    } else if (this.touchedOffsetY < takingVideoExtMinOffsetY) {
312      this.touchedOffsetY = takingVideoExtMinOffsetY
313    }
314    this.changeZoomRatioOnTakingVideoExt()
315  }
316
317  private takingVideoExtPgActionEnd(event?: GestureEvent): void {
318    if (!event) {
319      return;
320    }
321    this.touchedOffsetY = this.takingVideoExtCanvasHeight / 2
322    this.startOffsetY = 0
323    this.changeZoomRatioOnTakingVideoExt()
324  }
325
326  private subtractTouched(event?: TouchEvent): void {
327    if (!event) {
328      return;
329    }
330    if (event.type === TouchType.Down) {
331      this.subtractZoomRatio()
332    }
333    if (event.type === TouchType.Up) {
334      this.mAction.updateShowZoomFlag(false)
335    }
336  }
337
338  private subtractLongOnAction(event?: GestureEvent): void {
339    if (!event) {
340      return;
341    }
342    this.subtractZoomRatio()
343  }
344
345  private subtractLongOnActionEnd(): void {
346    this.mAction.updateShowZoomFlag(false)
347  }
348
349  private addTouched(event?: TouchEvent): void {
350    if (!event) {
351      return;
352    }
353    if (event.type === TouchType.Down) {
354      this.addZoomRatio()
355    }
356    if (event.type === TouchType.Up) {
357      this.mAction.updateShowZoomFlag(false)
358    }
359  }
360
361  private addLongOnAction(): void {
362    this.addZoomRatio()
363  }
364
365  private addLongOnActionEnd(): void {
366    this.mAction.updateShowZoomFlag(false)
367  }
368
369  private lpgOnAction(): void {
370    this.clearTimer()
371    this.mAction.updateShowZoomFlag(true)
372    this.baseZoomRatio = this.zoomRatio
373    this.offsetY = (this.zoomRatio - 1) * this.getZoomOffsetUnit()
374    this.lpgExp = true
375    this.pgExp = false
376    this.triggerRebuildNum = this.triggerRebuildNum + 0.0001
377  }
378
379  private lpgOnActionEnd(): void {
380    if (this.lpgTimer) {
381      clearTimeout(this.lpgTimer)
382    }
383    this.lpgTimer = setTimeout(() => {
384      if (this.lpgExp && !this.pgExp) {
385        this.mAction.updateShowZoomFlag(false)
386        this.triggerRebuildNum = this.triggerRebuildNum - 0.0001
387      }
388      this.lpgExp = false
389    }, 3000)
390  }
391
392  private pgOnActionStart(): void {
393    this.clearTimer()
394    this.mAction.updateShowZoomFlag(true)
395    this.mAction.updateShowZoomLabelValue(false)
396    this.baseZoomRatio = this.state.zoomRatio
397    this.pgExp = true
398    this.lpgExp = false
399  }
400
401  private pgOnActionUpdate(event?: GestureEvent): void {
402    if (!event) {
403      return;
404    }
405    this.offsetY = (this.baseZoomRatio - this.state.minZoomRatio) * this.getZoomOffsetUnit() + event.offsetY
406    this.updateZoomRatio()
407  }
408
409  private pgOnActionEnd(): void {
410    this.mAction.updateShowZoomLabelValue(true)
411    if (this.pgTimer) {
412      clearTimeout(this.pgTimer)
413    }
414    this.pgTimer = setTimeout(() => {
415      if (this.pgExp && !this.lpgExp) {
416        this.mAction.updateShowZoomFlag(false)
417      }
418      this.pgExp = false
419    }, 3000)
420  }
421
422  private mOnTouch(event: TouchEvent): void {
423    if (event.type === TouchType.Down) {
424      this.clearTimer()
425      this.mAction.updateShowZoomFlag(true)
426      this.pgExp = true
427      this.lpgExp = false
428
429      let y = event.touches[0].y
430      let zoomRatio = this.zoomRatio
431      if (this.state.videoState === 'beforeTakeVideo' && this.getCurrentCanvasType() === SHOW_NOT_TAKE_VIDEO_CANVAS) {
432        if (y < vp2px(36)) {
433          zoomRatio = this.state.maxZoomRatio
434        }
435        if (y > this.notTakeVideoExtCanvasHeight - vp2px(36)) {
436          zoomRatio = this.state.minZoomRatio
437        }
438        if (y > vp2px(36) && y < this.notTakeVideoExtCanvasHeight - vp2px(36)) {
439          this.offsetY = this.notTakeVideoExtCanvasHeight - y - this.getPadding()
440          this.updateZoomRatio()
441          return;
442        }
443      }
444      this.offsetY = (zoomRatio - 1) * this.getZoomOffsetUnit()
445      this.updateZoomRatio()
446    } else if (event.type === TouchType.Up) {
447      if (this.pgTimer) {
448        clearTimeout(this.pgTimer)
449      }
450      this.pgTimer = setTimeout(() => {
451        if (this.pgExp && !this.lpgExp) {
452          this.mAction.updateShowZoomFlag(false)
453        }
454        this.pgExp = false
455      }, 3000)
456    }
457  }
458
459  private getZoomBtnCenterY(): number {
460    if (this.getCurrentCanvasType() === SHOW_TAKING_VIDEO_CANVAS) {
461      return this.touchedOffsetY
462    }
463    if (this.offsetY === 0 && this.zoomRatio !== 1) {
464      this.offsetY = (this.zoomRatio - this.state.minZoomRatio) * this.getZoomOffsetUnit()
465    }
466    if (this.zoomRatio === 1 && this.offsetY !== 0) {
467      this.offsetY = 0
468    }
469    let padding = this.getPadding()
470    let result = this.notTakeVideoExtCanvasHeight - padding - this.offsetY
471    return result
472  }
473
474  private getZoomOffsetUnit(): number {
475    let padding = this.getPadding()
476    let fullHeight = this.notTakeVideoExtCanvasHeight - padding * 2 - this.mainDotRadius * 2
477    return fullHeight / (this.state.maxZoomRatio - this.state.minZoomRatio)
478  }
479
480  private updateZoomOffset(data: ZoomRatioStruct): void {
481    let offset = (data.zoomRatio - this.state.minZoomRatio) * this.getZoomOffsetUnit();
482    this.offsetY = offset;
483  }
484
485  private updateZoomState(data: VideoStateStruct): void {
486    if (data.videoState === 'beforeTakeVideo') {
487      this.clearTimer();
488      this.mAction.updateShowZoomFlag(false);
489      this.pgExp = false;
490    }
491  }
492
493  private clearTimer(): void {
494    if (this.pgTimer) {
495      clearTimeout(this.pgTimer)
496    }
497    if (this.lpgTimer) {
498      clearTimeout(this.lpgTimer)
499    }
500  }
501
502  private updateZoomRatio(): void {
503    let padding = this.getPadding()
504    let fullHeight = this.notTakeVideoExtCanvasHeight - padding * 2 - this.mainDotRadius * 2
505    this.curZoomRatio =
506      (this.offsetY / fullHeight) * (this.state.maxZoomRatio - this.state.minZoomRatio) + this.state.minZoomRatio
507    if (this.curZoomRatio > this.state.maxZoomRatio) {
508      this.curZoomRatio = this.state.maxZoomRatio
509    }
510    if (this.curZoomRatio < this.state.minZoomRatio) {
511      this.curZoomRatio = this.state.minZoomRatio
512    }
513    this.mAction.updateZoomRatio(this.curZoomRatio)
514  }
515
516  private getPadding(): number {
517    if (this.getCurrentCanvasType() === SHOW_NOT_TAKE_VIDEO_CANVAS) {
518      return 32
519    } else if (this.getCurrentCanvasType() === SHOW_TAKING_VIDEO_CANVAS) {
520      return 15.5
521    } else {
522      return 32
523    }
524  }
525
526  private getZoomText() {
527    return `${Number(this.zoomRatio.toFixed(1))}x`
528  }
529
530  private getZoomBtnRadius(): number {
531    if (!this.showZoomLabelValue) {
532      return 17.25
533    } else {
534      return 15.25
535    }
536  }
537
538  private onZoomRatioRefresh() {
539    if (this.getCurrentCanvasType() === this.refreshSwitchCanvas) {
540      this.refreshCanvas(this.refreshSwitchCanvas)
541    }
542  }
543
544  private canvasInit(mType: number): void {
545    this.refreshSwitchCanvas = mType
546    this.refreshCanvas(mType)
547  }
548
549  private refreshCanvas(mType: number): void {
550    switch (mType) {
551      case SHOW_NOT_TAKE_VIDEO_CANVAS:
552        this.notTakeVideoCanvas();
553        break;
554      case SHOW_TAKING_VIDEO_CANVAS:
555        this.takingVideoCanvas();
556        break;
557      default:
558        this.foldCanvas()
559    }
560  }
561
562  private notTakeVideoCanvas(): void {
563    this.notTakeVideoExtCanvasCxt.clearRect(0, 0, this.canvasWidth, this.notTakeVideoExtCanvasHeight)
564    this.notTakeVideoExtOffCanvasCxt.clearRect(0, 0, this.canvasWidth, this.notTakeVideoExtCanvasHeight)
565    this.notTakeVideoExtOffCanvasCxt.strokeStyle = '#ffffff'
566    this.notTakeVideoExtOffCanvasCxt.fillStyle = '#ffffff'
567    this.notTakeVideoExtOffCanvasCxt.lineWidth = 1.5
568    this.notTakeVideoExtOffCanvasCxt.beginPath()
569    this.notTakeVideoExtOffCanvasCxt.arc(this.canvasWidth / 2, this.getZoomBtnCenterY(), this.getZoomBtnRadius(), 0,
570      6.28)
571    this.notTakeVideoExtOffCanvasCxt.stroke()
572    if (this.showZoomLabelValue) {
573      this.notTakeVideoExtOffCanvasCxt.font = `bold ${vp2px(11)}px`
574      this.notTakeVideoExtOffCanvasCxt.textAlign = 'center'
575      this.notTakeVideoExtOffCanvasCxt.fillText(this.getZoomText(), this.canvasWidth / 2, this.getZoomBtnCenterY() + 5)
576    } else {
577      this.notTakeVideoExtOffCanvasCxt.beginPath()
578      this.notTakeVideoExtOffCanvasCxt.arc(this.canvasWidth / 2, this.getZoomBtnCenterY(), this.centerDotRadius, 0,
579        6.28)
580      this.notTakeVideoExtOffCanvasCxt.fill()
581    }
582
583    let spotCount =
584      (this.notTakeVideoExtCanvasHeight - this.getPadding() * 2 - this.mainDotRadius * 4 - this.dotSpacing) /
585        (this.dotSpacing + this.secDotRadius * 2) + 2
586    for (let i = 0; i < spotCount; i++) {
587      let spotCenter = 0
588      let spotRadius = 0
589      if (i === 0) {
590        spotRadius = this.mainDotRadius
591        spotCenter = this.notTakeVideoExtCanvasHeight - this.getPadding() - spotRadius
592        this.notTakeVideoExtOffCanvasCxt.font = `bold ${vp2px(11)}px`
593        this.notTakeVideoExtOffCanvasCxt.textAlign = 'right'
594        this.notTakeVideoExtOffCanvasCxt.fillText(`${this.state.minZoomRatio}x`,
595          this.canvasWidth / 2 - (!this.showZoomLabelValue ? 26 : 24), spotCenter)
596      } else if (i === spotCount - 1) {
597        spotRadius = this.mainDotRadius
598        spotCenter = this.getPadding() + spotRadius
599        this.notTakeVideoExtOffCanvasCxt.font = `bold ${vp2px(11)}px`
600        this.notTakeVideoExtOffCanvasCxt.textAlign = 'right'
601        this.notTakeVideoExtOffCanvasCxt.fillText(`${this.state.maxZoomRatio}x`,
602          this.canvasWidth / 2 - (!this.showZoomLabelValue ? 26 : 24), spotCenter)
603      } else {
604        spotRadius = this.secDotRadius
605        spotCenter = this.notTakeVideoExtCanvasHeight - this.getPadding() - this.mainDotRadius * 2 -
606          (2 * i - 1) * this.secDotRadius - i * this.dotSpacing
607        this.notTakeVideoExtOffCanvasCxt.globalAlpha = 0.2
608      }
609      if (spotCenter < this.getZoomBtnCenterY() - this.getZoomBtnRadius() ||
610        spotCenter > this.getZoomBtnCenterY() + this.getZoomBtnRadius()) {
611        this.notTakeVideoExtOffCanvasCxt.beginPath()
612        this.notTakeVideoExtOffCanvasCxt.arc(this.canvasWidth / 2, spotCenter, spotRadius, 0, 6.28)
613        this.notTakeVideoExtOffCanvasCxt.fill()
614      }
615      this.notTakeVideoExtOffCanvasCxt.globalAlpha = 1
616    }
617    this.notTakeVideoExtCanvasCxt.transferFromImageBitmap(this.notTakeVideoExtOffCanvasCxt.transferToImageBitmap())
618  }
619
620  private takingVideoCanvas(): void {
621    this.takingVideoExtCanvasCxt.clearRect(0, 0, this.canvasWidth, this.takingVideoExtCanvasHeight)
622    this.takingVideoExtOffCanvasCxt.clearRect(0, 0, this.canvasWidth, this.takingVideoExtCanvasHeight)
623    this.takingVideoExtOffCanvasCxt.strokeStyle = '#ffffff'
624    this.takingVideoExtOffCanvasCxt.fillStyle = '#ffffff'
625    this.takingVideoExtOffCanvasCxt.lineWidth = 1.5
626    this.takingVideoExtOffCanvasCxt.beginPath()
627    this.takingVideoExtOffCanvasCxt.arc(this.canvasWidth / 2, this.getZoomBtnCenterY(), this.getZoomBtnRadius(), 0,
628      6.28)
629    this.takingVideoExtOffCanvasCxt.stroke()
630    if (this.isShowZoomText) {
631      this.takingVideoExtOffCanvasCxt.beginPath()
632      this.takingVideoExtOffCanvasCxt.arc(this.canvasWidth / 2, this.getZoomBtnCenterY(), this.centerDotRadius, 0, 6.28)
633      this.takingVideoExtOffCanvasCxt.fill()
634    } else {
635      this.takingVideoExtOffCanvasCxt.font = `bold ${vp2px(11)}px`
636      this.takingVideoExtOffCanvasCxt.textAlign = 'center'
637      this.takingVideoExtOffCanvasCxt.fillText(this.getZoomText(), this.canvasWidth / 2, this.getZoomBtnCenterY() + 5)
638    }
639
640    let spotCount = 30
641    for (let i = 0; i < spotCount; i++) {
642      let spotCenter = 0
643      let spotRadius = 0
644      spotRadius = this.secDotRadius
645      spotCenter = this.getPadding() + (2 * i + 1) * this.secDotRadius + i * this.dotSpacing
646      this.takingVideoExtOffCanvasCxt.globalAlpha = 0.2
647      if (spotCenter < this.getZoomBtnCenterY() - this.getZoomBtnRadius() ||
648        spotCenter > this.getZoomBtnCenterY() + this.getZoomBtnRadius()) {
649        this.takingVideoExtOffCanvasCxt.beginPath()
650        this.takingVideoExtOffCanvasCxt.arc(this.canvasWidth / 2, spotCenter, spotRadius, 0, 6.28)
651        this.takingVideoExtOffCanvasCxt.fill()
652      }
653      this.takingVideoExtOffCanvasCxt.globalAlpha = 1
654    }
655
656    this.takingVideoExtCanvasCxt.transferFromImageBitmap(this.takingVideoExtOffCanvasCxt.transferToImageBitmap())
657  }
658
659  private foldCanvas(): void {
660    this.foldCanvasCxt.clearRect(0, 0, this.canvasWidth, this.foldCanvasHeight)
661    this.foldOffCanvasCxt.clearRect(0, 0, this.canvasWidth, this.foldCanvasHeight)
662    this.foldOffCanvasCxt.strokeStyle = '#ffffff'
663    this.foldOffCanvasCxt.fillStyle = '#ffffff'
664    this.foldOffCanvasCxt.lineWidth = 1.5
665    this.foldOffCanvasCxt.beginPath()
666    this.foldOffCanvasCxt.arc(this.canvasWidth / 2, this.foldCanvasHeight / 2, this.getZoomBtnRadius(), 0, 6.28)
667    this.foldOffCanvasCxt.stroke()
668
669    this.foldOffCanvasCxt.font = `bold ${vp2px(10)}px`
670    this.foldOffCanvasCxt.textAlign = 'center'
671    this.foldOffCanvasCxt.fillText(this.getZoomText(), this.canvasWidth / 2, this.foldCanvasHeight / 2 + 3)
672
673    let fullHeight = this.foldCanvasHeight / 2 - this.mainDotRadius
674    let spotCount =
675      (fullHeight - this.mainDotRadius * 2 - this.dotSpacing) / (this.dotSpacing + this.secDotRadius * 2) + 2
676    let spotOffset = (this.zoomRatio === this.state.maxZoomRatio) ? this.foldCanvasHeight / 2 + fullHeight
677      : this.foldCanvasHeight / 2
678    for (let i = 0; i < spotCount; i++) {
679      let spotCenter = 0
680      let spotRadius = 0
681      if (i === 0) {
682        spotRadius = this.mainDotRadius
683        spotCenter = spotOffset - spotRadius
684      } else if (i === spotCount - 1) {
685        spotRadius = this.mainDotRadius
686        spotCenter = spotOffset - this.mainDotRadius * 2 - (i - 1) * this.dotSpacing - (2 * i - 1) * this.secDotRadius +
687        this.secDotRadius - spotRadius
688      } else {
689        spotRadius = this.secDotRadius
690        spotCenter =
691          spotOffset - this.mainDotRadius * 2 - (i - 1) * this.dotSpacing - (2 * i - 1) * this.secDotRadius - spotRadius
692        this.foldOffCanvasCxt.globalAlpha = 0.2
693      }
694      if (spotCenter > this.foldCanvasHeight / 2 + this.getZoomBtnRadius() ||
695        spotCenter < this.foldCanvasHeight / 2 - this.getZoomBtnRadius()) {
696        this.foldOffCanvasCxt.beginPath()
697        this.foldOffCanvasCxt.arc(this.canvasWidth / 2, spotCenter, spotRadius, 0, 6.28)
698        this.foldOffCanvasCxt.fill()
699      }
700      this.foldOffCanvasCxt.globalAlpha = 1
701    }
702    this.foldCanvasCxt.transferFromImageBitmap(this.foldOffCanvasCxt.transferToImageBitmap())
703  }
704}