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