• 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 */
15import Matrix4 from '@ohos.matrix4'
16import { NavigationBar } from '../../../common/components/navigationBar'
17
18@Entry
19@Component
20struct TransformExample {
21  @State rotate: any = { x: 200, y: 200, z: 275 }
22  @State translate: any = { x: 200, y: 200, z: 200 }
23  @State transform: any = { x: 200, y: 200, z: 200 }
24  @State scale: any = { x: 1, y: 1, z: 1 }
25  @State rotateCenter: any = { X: 150, Y: 150 }
26  @State scaleCenter: any = { X: 150, Y: 150 }
27  @State angle: number = 360
28  @State index: number = 0
29  private controller: TabsController = new TabsController()
30  private init() {
31    this.rotate = { x: 200, y: 200, z: 275 }
32    this.transform = { x: 200, y: 200, z: 200 }
33    this.translate = { x: 200, y: 200, z: 200 }
34    this.scale = { x: 1, y: 1, z: 1 }
35    this.rotateCenter = { X: 150, Y: 150 }
36    this.scaleCenter = { X: 150, Y: 150 }
37    this.angle = 360
38  }
39
40  build() {
41    Column() {
42      NavigationBar({ title: '图形变换' })
43      Column() {
44        Scroll() {
45          Column() {
46            Column() {
47              Row()
48                .rotate({
49                  x: this.rotate.x - 200,
50                  y: this.rotate.y - 200,
51                  z: this.rotate.z - 200,
52                  centerX: `${this.rotateCenter.X - 100}%`,
53                  centerY: `${this.rotateCenter.Y - 100}%`,
54                  angle: this.angle - 360
55                })
56
57                .translate({
58                  x: this.translate.x - 200,
59                  y: this.translate.y - 200,
60                  z: this.translate.z - 200
61                })
62
63                .scale({
64                  x: this.scale.x,
65                  y: this.scale.y,
66                  z: this.scale.z,
67                  centerX: `${this.scaleCenter.X - 100}%`,
68                  centerY: `${this.scaleCenter.Y - 100}%`
69                })
70
71                .transform(Matrix4.identity)
72                .translate({
73                  x: this.transform.x - 200,
74                  y: this.transform.y - 200,
75                  z: this.transform.z - 200
76                })
77                .gesture(
78                PanGesture()
79                  .onActionUpdate((event: GestureEvent) => {
80                    this.translate.x = event.offsetX + 200
81                    this.translate.y = event.offsetY + 200
82                  })
83                )
84                .width(150)
85                .height(150)
86                .zIndex(999)
87                .backgroundColor('red')
88            }
89            .width('100%')
90            .height('100%')
91            .alignItems(HorizontalAlign.Center)
92            .justifyContent(FlexAlign.Start)
93            .gesture(
94            RotationGesture()
95              .onActionUpdate((event: GestureEvent) => {
96                this.angle = event.angle + 360
97              })
98            )
99          }
100          .width('100%')
101          .height('100%')
102          .backgroundColor('#FFB6C1')
103          .zIndex(999)
104          .gesture(
105          PinchGesture()
106            .onActionUpdate((event: GestureEvent) => {
107              this.scale.x = event.scale
108              this.scale.y = event.scale
109              this.scale.z = event.scale
110            })
111          )
112        }
113      }
114      .height('30%')
115      .width('100%')
116      .padding(18)
117      .backgroundColor('#FFFFFF')
118
119      Column() {
120        Tabs({ barPosition: BarPosition.Start, index: this.index, controller: this.controller }) {
121          TabContent() {
122            Column() {
123              Column() {
124                Row({ space: FlexAlign.SpaceBetween }) {
125                  Text('X')
126                    .fontWeight(FontWeight.Medium)
127                    .fontColor('#182431')
128                    .opacity(0.5)
129                    .fontSize('16fp')
130
131                  Blank()
132
133                  Text(`${(this.rotate.x - 200).toFixed(0)}`)
134                    .fontWeight(FontWeight.Regular)
135                    .fontColor('#000000')
136                    .fontSize('16fp')
137                }
138
139                Slider({
140                  value: this.rotate.x,
141                  min: 0,
142                  max: 400,
143                  step: 1,
144                  style: SliderStyle.OutSet
145                })
146                  .blockColor('#FFFFFF')
147                  .trackColor('#182431')
148                  .selectedColor('#007DFF')
149                  .width('100%')
150                  .showSteps(true)
151                  .showTips(false)
152                  .onChange((value: number) => {
153                    this.rotate.x = value
154                  })
155              }
156              .width('100%')
157              .justifyContent(FlexAlign.Center)
158              .padding({ left: '3%', right: '3%' })
159              .borderRadius(24)
160              .backgroundColor('#FFFFFF')
161              .margin(8)
162
163              Column() {
164                Row({ space: FlexAlign.SpaceBetween }) {
165                  Text('Y')
166                    .fontWeight(FontWeight.Medium)
167                    .fontColor('#182431')
168                    .opacity(0.5)
169                    .fontSize('16fp')
170
171                  Blank()
172
173                  Text(`${(this.rotate.y - 200).toFixed(0)}`)
174                    .fontWeight(FontWeight.Regular)
175                    .fontColor('#000000')
176                    .fontSize('16fp')
177                }
178
179                Slider({
180                  value: this.rotate.y,
181                  min: 0,
182                  max: 400,
183                  step: 1,
184                  style: SliderStyle.OutSet
185                })
186                  .blockColor('#FFFFFF')
187                  .trackColor('#182431')
188                  .selectedColor('#007DFF')
189                  .width('100%')
190                  .showSteps(true)
191                  .showTips(false)
192                  .onChange((value: number) => {
193                    this.rotate.y = value
194                  })
195              }
196              .width('100%')
197              .justifyContent(FlexAlign.Center)
198              .padding({ left: '3%', right: '3%' })
199              .borderRadius(24)
200              .backgroundColor('#FFFFFF')
201              .margin({ top: 8 })
202
203              Column() {
204                Row({ space: FlexAlign.SpaceBetween }) {
205                  Text('Z')
206                    .fontWeight(FontWeight.Medium)
207                    .fontColor('#182431')
208                    .opacity(0.5)
209                    .fontSize('16fp')
210
211                  Blank()
212
213                  Text(`${(this.rotate.z - 200).toFixed(0)}`)
214                    .fontWeight(FontWeight.Regular)
215                    .fontColor('#000000')
216                    .fontSize('16fp')
217                }
218
219                Slider({
220                  value: this.rotate.z,
221                  min: 0,
222                  max: 400,
223                  step: 1,
224                  style: SliderStyle.OutSet
225                })
226                  .blockColor('#FFFFFF')
227                  .trackColor('#182431')
228                  .selectedColor('#007DFF')
229                  .width('100%')
230                  .showSteps(true)
231                  .showTips(false)
232                  .onChange((value: number) => {
233                    this.rotate.z = value
234                  })
235              }
236              .justifyContent(FlexAlign.Center)
237              .width('100%')
238              .padding({ left: '3%', right: '3%' })
239              .borderRadius(24)
240              .backgroundColor('#FFFFFF')
241              .margin({ top: 8 })
242
243              Column() {
244                Row({ space: FlexAlign.SpaceBetween }) {
245                  Text('angle')
246                    .fontWeight(FontWeight.Medium)
247                    .fontColor('#182431')
248                    .opacity(0.5)
249                    .fontSize('16fp')
250
251                  Blank()
252
253                  Text(`${(this.angle - 360).toFixed(0)}`)
254                    .fontWeight(FontWeight.Regular)
255                    .fontColor('#000000')
256                    .fontSize('16fp')
257                }
258
259                Slider({
260                  value: this.angle,
261                  min: 0,
262                  max: 720,
263                  step: 1,
264                  style: SliderStyle.OutSet
265                })
266                  .blockColor('#FFFFFF')
267                  .trackColor('#182431')
268                  .selectedColor('#007DFF')
269                  .width('100%')
270                  .showSteps(true)
271                  .showTips(false)
272                  .onChange((value: number) => {
273                    this.angle = value
274                  })
275              }
276              .justifyContent(FlexAlign.Center)
277              .width('100%')
278              .padding({ left: '3%', right: '3%' })
279              .borderRadius(24)
280              .backgroundColor('#FFFFFF')
281              .margin({ top: 8 })
282
283              Column() {
284                Row({ space: FlexAlign.SpaceBetween }) {
285                  Text('centerX')
286                    .fontWeight(FontWeight.Medium)
287                    .fontColor('#182431')
288                    .opacity(0.5)
289                    .fontSize('16fp')
290
291                  Blank()
292
293                  Text('' + (this.rotateCenter.X - 100).toFixed(0) + '%')
294                    .fontWeight(FontWeight.Regular)
295                    .fontColor('#000000')
296                    .fontSize('16fp')
297                }
298                .justifyContent(FlexAlign.Center)
299
300                Slider({
301                  value: this.rotateCenter.X,
302                  min: 0,
303                  max: 200,
304                  step: 1,
305                  style: SliderStyle.OutSet
306                })
307                  .blockColor('#FFFFFF')
308                  .trackColor('#182431')
309                  .selectedColor('#007DFF')
310                  .width('100%')
311                  .showSteps(true)
312                  .showTips(false)
313                  .onChange((value: number) => {
314                    this.rotateCenter.X = value
315                  })
316              }
317              .width('100%')
318              .padding({ left: '3%', right: '3%', top: 12, bottom: 12 })
319              .borderRadius(24)
320              .backgroundColor('#FFFFFF')
321              .margin({ top: 8 })
322
323              Column() {
324                Row({ space: FlexAlign.SpaceBetween }) {
325                  Text('centerY')
326                    .fontWeight(FontWeight.Medium)
327                    .fontColor('#182431')
328                    .opacity(0.5)
329                    .fontSize('16fp')
330
331                  Blank()
332
333                  Text('' + (this.rotateCenter.Y - 100).toFixed(0) + '%')
334                    .fontWeight(FontWeight.Regular)
335                    .fontColor('#000000')
336                    .fontSize('16fp')
337                }
338
339                Slider({
340                  value: this.rotateCenter.Y,
341                  min: 0,
342                  max: 200,
343                  step: 1,
344                  style: SliderStyle.OutSet
345                })
346                  .blockColor('#FFFFFF')
347                  .trackColor('#182431')
348                  .selectedColor('#007DFF')
349                  .width('100%')
350                  .showSteps(true)
351                  .showTips(false)
352                  .onChange((value: number) => {
353                    this.rotateCenter.Y = value
354                  })
355              }
356              .justifyContent(FlexAlign.Center)
357              .width('100%')
358              .padding({ left: '3%', right: '3%' })
359              .borderRadius(24)
360              .backgroundColor('#FFFFFF')
361              .margin({ top: 8 })
362            }
363          }.tabBar('rotate')
364
365          TabContent() {
366            Column() {
367              Column() {
368                Row({ space: FlexAlign.SpaceBetween }) {
369                  Text('X')
370                    .fontWeight(FontWeight.Medium)
371                    .fontColor('#182431')
372                    .opacity(0.5)
373                    .fontSize('16fp')
374
375                  Blank()
376
377                  Text('' + (this.translate.x - 200).toFixed(0))
378                    .fontSize('16fp')
379                    .fontWeight(FontWeight.Medium)
380                }
381
382                Slider({
383                  value: this.translate.x,
384                  min: 0,
385                  max: 400,
386                  step: 0.1,
387                  style: SliderStyle.OutSet
388                })
389                  .blockColor('#FFFFFF')
390                  .trackColor('#182431')
391                  .selectedColor('#007DFF')
392                  .width('100%')
393                  .showSteps(true)
394                  .showTips(false)
395                  .onChange((value: number) => {
396                    this.translate.x = value
397                  })
398              }
399              .width('100%')
400              .padding({ left: '3%', right: '3%', top: 12, bottom: 12 })
401              .borderRadius(24)
402              .backgroundColor('#FFFFFF')
403              .margin(8)
404
405              Column() {
406                Row({ space: FlexAlign.SpaceBetween }) {
407                  Text('Y')
408                    .fontWeight(FontWeight.Medium)
409                    .fontColor('#182431')
410                    .opacity(0.5)
411                    .fontSize('16fp')
412
413                  Blank()
414
415                  Text('' + (this.translate.y - 200).toFixed(0))
416                    .fontSize('16fp')
417                    .fontWeight(FontWeight.Medium)
418                }
419
420                Slider({
421                  value: this.translate.y,
422                  min: 0,
423                  max: 400,
424                  step: 1,
425                  style: SliderStyle.OutSet
426                })
427                  .blockColor('#FFFFFF')
428                  .trackColor('#182431')
429                  .selectedColor('#007DFF')
430                  .width('100%')
431                  .showSteps(true)
432                  .showTips(false)
433                  .onChange((value: number) => {
434                    this.translate.y = value
435                  })
436              }
437              .width('100%')
438              .padding({ left: '3%', right: '3%', top: 12, bottom: 12 })
439              .borderRadius(24)
440              .backgroundColor('#FFFFFF')
441              .margin(8)
442
443              Column() {
444                Row({ space: FlexAlign.SpaceBetween }) {
445                  Text('Z')
446                    .fontWeight(FontWeight.Medium)
447                    .fontColor('#182431')
448                    .opacity(0.5)
449                    .fontSize('16fp')
450
451                  Blank()
452
453                  Text('' + (this.translate.z - 200).toFixed(0))
454                    .fontSize('16fp')
455                    .fontWeight(FontWeight.Medium)
456                }
457
458                Slider({
459                  value: this.translate.z,
460                  min: 0,
461                  max: 400,
462                  step: 1,
463                  style: SliderStyle.OutSet
464                })
465                  .blockColor('#FFFFFF')
466                  .trackColor('#182431')
467                  .selectedColor('#007DFF')
468                  .width('100%')
469                  .showSteps(true)
470                  .showTips(false)
471                  .onChange((value: number) => {
472                    this.translate.z = value
473                  })
474              }
475              .width('100%')
476              .padding({ left: '3%', right: '3%', top: 12, bottom: 12 })
477              .borderRadius(24)
478              .backgroundColor('#FFFFFF')
479              .margin(8)
480            }
481          }.tabBar('translate')
482
483          TabContent() {
484            Column() {
485              Row({ space: FlexAlign.SpaceBetween }) {
486                Text('X')
487                  .fontWeight(FontWeight.Medium)
488                  .fontColor('#182431')
489                  .opacity(0.5)
490                  .fontSize('16fp')
491
492                Blank()
493
494                Column() {
495                  Counter() {
496                    Text(this.scale.x.toFixed(1).toString()).fontSize(16)
497                  }
498                  .height(24)
499                  .onInc(() => {
500                      this.scale.x < 5 ? this.scale.x += 0.1 : this.scale.x
501
502                  })
503                  .onDec(() => {
504                      this.scale.x > 0.1 ? this.scale.x -= 0.1 : this.scale.x
505                  })
506                }
507              }
508              .alignItems(VerticalAlign.Center)
509              .width('100%')
510              .padding({ left: '3%', right: '3%', top: 12, bottom: 12 })
511              .borderRadius(24)
512              .backgroundColor('#FFFFFF')
513              .margin(8)
514
515              Row({ space: FlexAlign.SpaceBetween }) {
516                Text('Y')
517                  .fontWeight(FontWeight.Medium)
518                  .fontColor('#182431')
519                  .opacity(0.5)
520                  .fontSize('16fp')
521
522                Blank()
523
524                Column() {
525                  Counter() {
526                    Text(this.scale.y.toFixed(1).toString()).fontSize(16)
527                  }
528                  .height(24)
529                  .onInc(() => {
530                      this.scale.y < 5 ? this.scale.y += 0.1 : this.scale.y
531
532                  })
533                  .onDec(() => {
534                      this.scale.y > 0.1 ? this.scale.y -= 0.1 : this.scale.y
535                  })
536                }
537              }
538              .alignItems(VerticalAlign.Center)
539              .width('100%')
540              .padding({ left: '3%', right: '3%', top: 12, bottom: 12 })
541              .borderRadius(24)
542              .backgroundColor('#FFFFFF')
543              .margin(8)
544
545              Row({ space: FlexAlign.SpaceBetween }) {
546                Text('Z')
547                  .fontWeight(FontWeight.Medium)
548                  .fontColor('#182431')
549                  .opacity(0.5)
550                  .fontSize('16fp')
551
552                Blank()
553
554                Column() {
555                  Counter() {
556                    Text(this.scale.z.toFixed(1).toString()).fontSize(16)
557                  }
558                  .height(24)
559                  .onInc(() => {
560                      this.scale.z < 5 ? this.scale.z += 0.1 : this.scale.z
561
562                  })
563                  .onDec(() => {
564                      this.scale.z > 0.1 ? this.scale.z -= 0.1 : this.scale.z
565                  })
566                }
567              }
568              .alignItems(VerticalAlign.Center)
569              .width('100%')
570              .padding({ left: '3%', right: '3%', top: 12, bottom: 12 })
571              .borderRadius(24)
572              .backgroundColor('#FFFFFF')
573              .margin(8)
574
575              Column() {
576                Row({ space: FlexAlign.SpaceBetween }) {
577                  Text('centerX')
578                    .fontWeight(FontWeight.Medium)
579                    .fontColor('#182431')
580                    .opacity(0.5)
581                    .fontSize('16fp')
582
583                  Blank()
584
585                  Text('' + (this.scaleCenter.X - 100).toFixed(0) + '%')
586                    .fontSize('16fp')
587                    .fontWeight(FontWeight.Medium)
588                }
589
590                Slider({
591                  value: this.scaleCenter.X,
592                  min: 0,
593                  max: 200,
594                  step: 1,
595                  style: SliderStyle.OutSet
596                })
597                  .blockColor('#FFFFFF')
598                  .trackColor('#182431')
599                  .selectedColor('#007DFF')
600                  .width('100%')
601                  .showSteps(true)
602                  .showTips(false)
603                  .onChange((value: number) => {
604                    this.scaleCenter.X = value
605                  })
606              }
607              .width('100%')
608              .padding({ left: '3%', right: '3%', top: 12, bottom: 12 })
609              .borderRadius(24)
610              .backgroundColor('#FFFFFF')
611              .margin(8)
612
613              Column() {
614                Row({ space: FlexAlign.SpaceBetween }) {
615                  Text('centerY')
616                    .fontWeight(FontWeight.Medium)
617                    .fontColor('#182431')
618                    .opacity(0.5)
619                    .fontSize('16fp')
620
621                  Blank()
622
623                  Text('' + (this.scaleCenter.Y - 100).toFixed(0) + '%')
624                    .fontSize('16fp')
625                    .fontWeight(FontWeight.Medium)
626                }
627
628                Slider({
629                  value: this.scaleCenter.Y,
630                  min: 0,
631                  max: 200,
632                  step: 1,
633                  style: SliderStyle.OutSet
634                })
635                  .blockColor('#FFFFFF')
636                  .trackColor('#182431')
637                  .selectedColor('#007DFF')
638                  .width('100%')
639                  .showSteps(true)
640                  .showTips(false)
641                  .onChange((value: number) => {
642                    this.scaleCenter.Y = value
643                  })
644              }
645              .width('100%')
646              .padding({ left: '3%', right: '3%', top: 12, bottom: 12 })
647              .borderRadius(24)
648              .backgroundColor('#FFFFFF')
649              .margin(8)
650            }
651          }.tabBar('scale')
652
653          TabContent() {
654            Column() {
655              Column() {
656                Row({ space: FlexAlign.SpaceBetween }) {
657                  Text('X:')
658                    .fontWeight(FontWeight.Medium)
659                    .fontColor('#182431')
660                    .opacity(0.5)
661                    .fontSize('16fp')
662
663                  Blank()
664
665                  Text('' + (this.transform.x - 200).toFixed(0))
666                    .fontSize('16fp')
667                    .fontWeight(FontWeight.Medium)
668                }
669
670                Slider({
671                  value: this.transform.x,
672                  min: 0,
673                  max: 400,
674                  step: 1,
675                  style: SliderStyle.OutSet
676                })
677                  .blockColor('#FFFFFF')
678                  .trackColor('#182431')
679                  .selectedColor('#007DFF')
680                  .width('100%')
681                  .showSteps(true)
682                  .showTips(false)
683                  .onChange((value: number) => {
684                    this.transform.x = value
685                  })
686              }
687              .width('100%')
688              .padding({ left: '3%', right: '3%', top: 12, bottom: 12 })
689              .borderRadius(24)
690              .backgroundColor('#FFFFFF')
691              .margin(8)
692
693              Column() {
694                Row({ space: FlexAlign.SpaceBetween }) {
695                  Text('Y')
696                    .fontWeight(FontWeight.Medium)
697                    .fontColor('#182431')
698                    .opacity(0.5)
699                    .fontSize('16fp')
700
701                  Blank()
702
703                  Text('' + (this.transform.y - 200).toFixed(0))
704                    .fontSize('16fp')
705                    .fontWeight(FontWeight.Medium)
706                }
707
708                Slider({
709                  value: this.transform.y,
710                  min: 0,
711                  max: 400,
712                  step: 1,
713                  style: SliderStyle.OutSet
714                })
715                  .blockColor('#FFFFFF')
716                  .trackColor('#182431')
717                  .selectedColor('#007DFF')
718                  .width('100%')
719                  .showSteps(true)
720                  .showTips(false)
721                  .onChange((value: number) => {
722                    this.transform.y = value
723                  })
724              }
725              .width('100%')
726              .padding({ left: '3%', right: '3%', top: 12, bottom: 12 })
727              .borderRadius(24)
728              .backgroundColor('#FFFFFF')
729              .margin(8)
730
731              Column() {
732                Row({ space: FlexAlign.SpaceBetween }) {
733                  Text('Z')
734                    .fontWeight(FontWeight.Medium)
735                    .fontColor('#182431')
736                    .opacity(0.5)
737                    .fontSize('16fp')
738
739                  Blank()
740
741                  Text('' + (this.transform.z - 200).toFixed(0))
742                    .fontSize('16fp')
743                    .fontWeight(FontWeight.Medium)
744                }
745
746                Slider({
747                  value: this.transform.z,
748                  min: 0,
749                  max: 400,
750                  step: 1,
751                  style: SliderStyle.OutSet
752                })
753                  .blockColor('#FFFFFF')
754                  .trackColor('#182431')
755                  .selectedColor('#007DFF')
756                  .width('100%')
757                  .showSteps(true)
758                  .showTips(false)
759                  .onChange((value: number) => {
760                    this.transform.z = value
761                  })
762              }
763              .width('100%')
764              .padding({ left: '3%', right: '3%', top: 12, bottom: 12 })
765              .borderRadius(24)
766              .backgroundColor('#FFFFFF')
767              .margin(8)
768            }
769          }.tabBar('transform')
770        }
771        .vertical(false)
772        .scrollable(true)
773        .barMode(BarMode.Fixed)
774        .barWidth(360)
775        .animationDuration(400)
776        .width('100%')
777        .backgroundColor(0xF5F5F5)
778        .onChange((index: number) => {
779          this.init()
780        })
781      }
782      .width('100%')
783      .height('65%')
784      .margin({ top: 10 })
785    }
786    .height('100%')
787    .backgroundColor('#F1F3F5')
788    .padding({ left: '3%', right: '3%', bottom: 10 })
789  }
790
791  pageTransition() {
792    PageTransitionEnter({ duration: 370, curve: Curve.Friction })
793      .slide(SlideEffect.Bottom)
794      .opacity(0.0)
795
796    PageTransitionExit({ duration: 370, curve: Curve.Friction })
797      .slide(SlideEffect.Bottom)
798      .opacity(0.0)
799  }
800}