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