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