• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# CanvasRenderingContext2D对象
2
3
4使用CanvasRenderingContext2D在Canvas画布组件上进行绘制,绘制对象可以是图形、文本、线段、图片等。具体请参考[CanvasRenderingContext2D对象](../reference/arkui-js/js-components-canvas-canvasrenderingcontext2d.md)。
5
6
7## 画线段
8
9使用moveTo和lineTo画出一条线段,当使用closePath方法时会结束当前路径形成一个封闭图形 。设置quadraticCurveTo(二次贝赛尔曲线)或bezierCurveTo(三次贝赛尔曲线)的值组成图形。
10
11
12```html
13<!-- xxx.hml -->
14<div class="container">
15  <canvas ref="canvas1"></canvas>
16  <select @change="change">
17    <option value="value1"> line </option>
18    <option value="value2"> quadratic </option>
19    <option value="value3"> bezier </option>
20    <option value="value4"> arc/ellipse </option>
21    <option value="value5"> lineJoin/miterLimit </option>
22  </select>
23</div>
24```
25
26
27```css
28/* xxx.css */
29.container{
30  width: 100%;
31  height: 100%;
32  flex-direction: column;
33  justify-content: center;
34  align-items: center;
35  background-color: #F1F3F5;
36}
37canvas{
38  width: 600px;
39  height: 500px;
40  background-color: #fdfdfd;
41  border: 5px solid red;
42}
43select{
44  margin-top: 50px;
45  width: 250px;
46  height: 100px;
47  background-color: white;
48}
49```
50
51
52```js
53// xxx.js
54export default {
55  data:{
56    el: null,
57    ctx: null,
58  },
59  onShow(){
60    this.el = this.$refs.canvas1;
61    this.ctx = this.el.getContext("2d",{antialias: true});
62    // 清除画布上的内容
63    this.ctx.clearRect(0, 0, 600, 500);
64    // 创建一个新的绘制路径
65    this.ctx.beginPath();
66    // 线端点以方形结束
67    this.ctx.lineCap = 'butt';
68    // 描边的宽度
69    this.ctx.lineWidth = 15;
70    // 创建一个新的绘制路径
71    this.ctx.beginPath();
72    // 路径从当前点移动到指定点
73    this.ctx.moveTo(200, 100);
74    // 从当前点到指定点进行路径连接
75    this.ctx.lineTo(400, 100);
76    // 边框绘制
77    this.ctx.stroke();
78    this.ctx.beginPath();
79    // 线端点以圆形结束
80    this.ctx.lineCap = 'round';
81    this.ctx.moveTo(200, 200);
82    this.ctx.lineTo(400, 200);
83    this.ctx.stroke();
84    // 线端点以方形结束
85    this.ctx.beginPath();
86    this.ctx.lineCap = 'square';
87    this.ctx.moveTo(200, 300);
88    this.ctx.lineTo(400, 300);
89    this.ctx.stroke();
90  },
91  change(e){
92    if(e.newValue == 'value1'){
93      this.el = this.$refs.canvas1;
94      this.ctx = this.el.getContext("2d",{antialias: true});
95      this.ctx.clearRect(0, 0, 600, 500);
96      // 上
97      this.ctx.beginPath();
98      this.ctx.lineCap = 'butt';
99      this.ctx.moveTo(200, 100);
100      this.ctx.lineTo(400, 100);
101      this.ctx.stroke();
102      // 中
103      this.ctx.beginPath();
104      this.ctx.lineCap = 'round';
105      this.ctx.moveTo(200, 200);
106      this.ctx.lineTo(400, 200);
107      this.ctx.stroke();
108      // 下
109      this.ctx.beginPath();
110      this.ctx.lineCap = 'square';
111      this.ctx.moveTo(200, 300);
112      this.ctx.lineTo(400, 300);
113      this.ctx.stroke();
114    }else if(e.newValue == 'value2'){
115      this.ctx.clearRect(0, 0, 600, 500);
116      // 上
117      this.ctx.beginPath();
118      this.ctx.moveTo(100, 150);
119      // 二次贝赛尔曲线的路径
120      this.ctx.quadraticCurveTo(300, 50, 500, 150);
121      this.ctx.stroke();
122      // 左
123      this.ctx.beginPath();
124      this.ctx.moveTo(200, 150);
125      this.ctx.quadraticCurveTo(250, 250, 250, 400);
126      this.ctx.stroke();
127      // 右
128      this.ctx.beginPath();
129      this.ctx.moveTo(400, 150);
130      this.ctx.quadraticCurveTo(350, 250, 350, 400);
131      this.ctx.stroke();
132    }else if(e.newValue == 'value3'){
133      this.ctx.clearRect(0, 0, 600, 500);
134      // 下
135      this.ctx.beginPath();
136      this.ctx.moveTo(100, 200);
137      // 三次贝赛尔曲线的路径
138      this.ctx.bezierCurveTo(150, 100, 200, 100,250, 200);
139      this.ctx.stroke();
140      // 左
141      this.ctx.beginPath();
142      this.ctx.moveTo(350, 200);
143      this.ctx.bezierCurveTo(400, 100, 450, 100,500, 200);
144      this.ctx.stroke();
145      // 右
146      this.ctx.beginPath();
147      this.ctx.moveTo(200, 350);
148      this.ctx.bezierCurveTo(250, 500, 350, 500, 400, 350);
149      this.ctx.stroke();
150    }else if(e.newValue == 'value4'){
151      this.ctx.clearRect(0, 0, 600, 500);
152      this.ctx.beginPath();
153      this.ctx.moveTo(100, 200);
154      // 弧线
155      this.ctx.arcTo(150, 300, 350, 300, 150);
156      this.ctx.stroke();
157      this.ctx.beginPath();
158      // 椭圆
159      this.ctx.ellipse(400, 250, 50, 100, Math.PI * 0.25, Math.PI * 0.5 , Math.PI , 1);
160      this.ctx.stroke();
161    }else if(e.newValue == 'value5'){
162      this.ctx.clearRect(0, 0, 600, 500);
163      // 左上
164      this.ctx.beginPath();
165      // 在线段相连处绘制一个扇形
166      this.ctx.lineJoin = 'round';
167      this.ctx.moveTo(100, 100);
168      this.ctx.lineTo(200, 200);
169      this.ctx.lineTo(100, 250);
170      this.ctx.stroke();
171      // 左下
172      this.ctx.beginPath();
173      // 在线段相连处使用三角形为底填充
174      this.ctx.lineJoin = 'bevel';
175      this.ctx.moveTo(100, 300);
176      this.ctx.lineTo(200, 400);
177      this.ctx.lineTo(100, 450);
178      this.ctx.stroke();
179      // 右上
180      this.ctx.beginPath();
181      //线条相交处内角和外角的距离
182      this.ctx.lineJoin = 'miter';
183      this.ctx.miterLimit = 3;
184      this.ctx.moveTo(400, 100);
185      this.ctx.lineTo(450, 200);
186      this.ctx.lineTo(400, 250);
187      // 结束当前路径形成一个封闭路径
188      this.ctx.closePath();
189      this.ctx.stroke();
190      // 右下
191      this.ctx.beginPath();
192      this.ctx.lineJoin = 'miter';
193      this.ctx.miterLimit = 10;
194      this.ctx.moveTo(400, 300);
195      this.ctx.lineTo(450, 400);
196      this.ctx.lineTo(400, 450);
197      this.ctx.closePath();
198      this.ctx.stroke();
199    }
200  },
201}
202```
203
204![zh-cn_image_0000001223064173](figures/zh-cn_image_0000001223064173.gif)
205
206
207## 画边框
208
209全局定义画布(el)及画笔(ctx),初始化创建一个边框宽度为5的长方形。对边框的宽度(lineWidth)、颜色(strokeStyle)、虚化程度(setLineDash)进行改变,选用select组件添加change事件,下拉选择时触发change事件后画出改变后的图形。
210
211
212
213```html
214<!-- xxx.hml -->
215<div class="container">
216  <canvas ref="canvas1"></canvas>
217  <select @change="change">
218    <option value="value1">strokeRect</option>
219    <option value="value2">arc</option>
220    <option value="value3">lineDashRect</option>
221    <option value="value4">fillRect</option>
222  </select>
223</div>
224```
225
226
227
228```css
229/* xxx.css */
230.container{
231  width: 100%;
232  height: 100%;
233  flex-direction: column;
234  justify-content: center;
235  align-items: center;
236  background-color: #F1F3F5;
237}
238canvas{
239  width: 600px;
240  height: 500px;
241  background-color: #fdfdfd;
242  border: 5px solid red;
243}
244select{
245  margin-top: 50px;
246  width: 250px;
247  height: 100px;
248  background-color: white;
249}
250```
251
252
253
254```js
255// xxx.js
256export default {
257  data:{
258    el: null,
259    ctx: null,
260  },
261  onShow(){
262    this.el = this.$refs.canvas1;
263    this.ctx = this.el.getContext("2d",{antialias: true});
264    this.ctx.lineWidth = 5;
265    this.ctx.strokeRect(200, 150, 200, 200);
266  },
267  change(e){
268    if(e.newValue == 'value1'){
269      // 清除画布上的内容
270      this.ctx.clearRect(0,0,600,500);
271      // 边框宽度
272      this.ctx.lineWidth = 5;
273      // 边框颜色
274      this.ctx.strokeStyle = '#110000';
275      // 边框的虚化程度
276      this.ctx.setLineDash([0,0]);
277      // 画具有边框的矩形
278      this.ctx.strokeRect(200, 150, 200, 200);
279    }else if (e.newValue == 'value2'){
280      this.ctx.clearRect(0,0,600,500);
281      this.ctx.lineWidth = 30;
282      this.ctx.strokeStyle = '#0000ff';
283      this.ctx.setLineDash([0,0]);
284      // 画圆
285      this.ctx.arc(300, 250, 150,0,6.28);
286      //进行边框绘制
287      this.ctx.stroke();
288    }else if (e.newValue == 'value3'){
289      this.ctx.clearRect(0,0,600,500);
290      this.ctx.lineWidth = 5;
291      this.ctx.setLineDash([5,5]);
292      this.ctx.strokeRect(200, 150, 200, 200);
293    }else if (e.newValue == 'value4'){
294      this.ctx.clearRect(0,0,600,500);
295      // 画一个有填充颜色的矩形
296      this.ctx.fillStyle = '#0000ff';
297      this.ctx.fillRect(200, 150, 200, 200);
298    }
299  },
300}
301```
302
303
304![zh-cn_image_0000001177466006](figures/zh-cn_image_0000001177466006.gif)
305
306
307## 填充渐变色
308
309添加createLinearGradient和createRadialGradient属性创建渐变容器,接着用addColorStop方法添加多个色块组成渐变色,再设置fillStyle为gradient将渐变色填充到矩形中,最后设置阴影的模糊级别(shadowBlur)、阴影颜色(shadowColor)及阴影偏移量(shadowOffset)。
310
311
312```html
313<!-- xxx.hml -->
314<div class="container">
315  <canvas ref="canvas1"></canvas>
316  <select @change="change">
317    <option value="value1">LinearGradient</option>
318    <option value="value2">RadialGradient</option>
319    <option value="value3">shadowBlur</option>
320    <option value="value4">shadowOffset</option>
321  </select>
322</div>
323```
324
325
326```css
327/* xxx.css */
328.container{
329  width: 100%;
330  height: 100%;
331  flex-direction: column;
332  justify-content: center;
333  align-items: center;
334  background-color: #F1F3F5;
335}
336canvas{
337  width: 600px;
338  height: 500px;
339  background-color: #fdfdfd;
340  border: 5px solid red;
341}
342select{
343  margin-top: 50px;
344  width: 250px;
345  height: 100px;
346  background-color: white;
347}
348```
349
350
351```js
352// xxx.js
353export default {
354  data:{
355    el: null,
356    ctx: null,
357  },
358  onShow(){
359    this.el = this.$refs.canvas1;
360    this.ctx = this.el.getContext("2d",{antialias: true});
361    // 创建一个线性渐变色
362    let gradient = this.ctx.createLinearGradient(100,100, 400,300);
363    // 添加渐变颜色
364    gradient.addColorStop(0.0, 'red');
365    gradient.addColorStop(0.7, 'white');
366    gradient.addColorStop(1.0, 'green');
367    // 填充颜色为渐变色
368    this.ctx.fillStyle = gradient;
369    this.ctx.fillRect(100, 100, 400, 300);
370  },
371  change(e){
372    if(e.newValue == 'value1'){
373      // 清除画布上的内容
374      this.ctx.clearRect(0,0,600,500);
375      let gradient = this.ctx.createLinearGradient(100,100, 400,300);
376      gradient.addColorStop(0.0, 'red');
377      gradient.addColorStop(0.7, 'white');
378      gradient.addColorStop(1.0, 'green');
379      this.ctx.fillStyle = gradient;
380      // 设置绘制阴影时的模糊级别
381      this.ctx.shadowBlur = 0;
382      // 绘制阴影时和原有对象的垂直偏移值
383      this.ctx.shadowOffsetY = 0;
384      // 绘制阴影时和原有对象的水平偏移值
385      this.ctx.shadowOffsetX = 0;
386      this.ctx.fillRect(100, 100, 400, 300);
387    }else if(e.newValue == 'value2'){
388      this.ctx.clearRect(0,0,600,500);
389      // 创建一个径向渐变色
390      let gradient = this.ctx.createRadialGradient(300,250,20,300,250,100);
391      gradient.addColorStop(0.0, 'red');
392      gradient.addColorStop(0.7, 'white');
393      gradient.addColorStop(1.0, 'green');
394      this.ctx.shadowBlur = 0;
395      this.ctx.shadowOffsetY = 0;
396      this.ctx.shadowOffsetX = 0;
397      this.ctx.fillStyle = gradient;
398      this.ctx.fillRect(100, 100, 400, 300);
399    }else if(e.newValue == 'value3'){
400      this.ctx.clearRect(0,0,600,500);
401      let gradient = this.ctx.createLinearGradient(100,100, 400,400);
402      gradient.addColorStop(0.0, 'red');
403      gradient.addColorStop(0.5, 'white');
404      gradient.addColorStop(1, '#17ea35');
405      // 设置绘制阴影时的模糊级别
406      this.ctx.shadowBlur = 30;
407      // 绘制阴影时的阴影颜色
408      this.ctx.shadowColor = 'rgb(229, 16, 16)';
409      this.ctx.fillStyle = gradient;
410      this.ctx.fillRect(100, 100, 400, 300);
411    }else if(e.newValue == 'value4'){
412      this.ctx.clearRect(0,0,600,500);
413      this.ctx.clearRect(0,0,600,500);
414      let gradient = this.ctx.createRadialGradient(300,250,20,300,250,200);
415      gradient.addColorStop(0.0, 'red');
416      gradient.addColorStop(0.5, 'white');
417      gradient.addColorStop(1, '#17ea35');
418      // 设置绘制阴影时的模糊级别
419      this.ctx.shadowBlur = 30;
420      this.ctx.shadowOffsetY = 30;
421      // 绘制阴影时的阴影颜色
422      this.ctx.shadowColor = 'rgb(23, 1, 1)';
423      this.ctx.fillStyle = gradient;
424      this.ctx.fillRect(100, 100, 400, 300);
425    }
426  },
427}
428```
429
430![zh-cn_image_0000001222985801](figures/zh-cn_image_0000001222985801.gif)
431
432
433## 填充文字
434
435先创建文本,再用fillText方法把文字写在画布上。通过globalAlpha属性改变基线透明度,使基线不会挡住文字,再设置textAlign和textBaseline属性确定文字基于基线的位置。
436
437
438```html
439<!-- xxx.hml -->
440<div class="container">
441  <canvas ref="canvas1"></canvas>
442  <select @change="change">
443    <option value="value1">text</option>
444    <option value="value2">textBaseline</option>
445    <option value="value3">textAlign</option>
446  </select>
447</div>
448```
449
450
451```css
452/* xxx.css */
453.container{
454  width: 100%;
455  height: 100%;
456  flex-direction: column;
457  justify-content: center;
458  align-items: center;
459  background-color: #F1F3F5;
460}
461canvas{
462  width: 600px;
463  height: 500px;
464  background-color: #fdfdfd;
465  border: 5px solid red;
466}
467select{
468  margin-top: 50px;
469  width: 250px;
470  height: 100px;
471  background-color: white;
472}
473```
474
475
476```js
477// xxx.js
478export default {
479  data:{
480    el: null,
481    ctx: null,
482  },
483  onShow(){
484    this.el = this.$refs.canvas1;
485    this.ctx = this.el.getContext("2d",{antialias: true});
486    // 创建文本
487    let text = "Hello World";
488    // 设置字体
489    this.ctx.font = '30px';
490    this.ctx.fillText("with:"+this.ctx.measureText(text).width, 200, 300);
491    // 填充字体文本
492    this.ctx.fillText(text, 200, 250);
493  },
494  change(e){
495    if(e.newValue == 'value1'){
496      // 清除画布上的内容
497      this.ctx.clearRect(0,0,600,500);
498      // 开始新的路径
499      this.ctx.beginPath();
500      // 初始化textAlign值
501      this.ctx.textAlign = 'left';
502      // 初始化textBaseline
503      this.ctx.textBaseline = 'alphabetic';
504      // 设置字体
505      this.ctx.font = '30px';
506      let text = "Hello World";
507      // 获取字体width
508      this.ctx.fillText("with:"+this.ctx.measureText(text).width, 200, 300);
509      // 填充字体文本
510      this.ctx.fillText(text, 200, 250);
511    }else if(e.newValue == 'value2'){
512      this.ctx.clearRect(0,0,600,500);
513      this.ctx.beginPath();
514      // 设置透明度
515      this.ctx.globalAlpha = 0.1;
516      // 设置线宽度
517      this.ctx.lineWidth = 10;
518      // 设置线段颜色
519      this.ctx.strokeStyle = '#0000ff';
520      // 从当前点移动到指定点
521      this.ctx.moveTo(0, 240);
522      // 当前点到指定点进行路径连接
523      this.ctx.lineTo(600, 240);
524      this.ctx.stroke();
525      this.ctx.font = '35px';
526      this.ctx.globalAlpha = 1;
527      // 初始化textAlign值
528      this.ctx.textAlign = 'left';
529      // 设置textBaseline
530      this.ctx.textBaseline = 'top';
531      this.ctx.fillText('Top', 50, 240);
532      this.ctx.textBaseline = 'bottom';
533      this.ctx.fillText('Bottom', 200, 240);
534      this.ctx.textBaseline = 'middle';
535      this.ctx.fillText('Middle', 400, 240);
536    }else if(e.newValue == 'value3'){
537      // 清除画布上的内容
538      this.ctx.clearRect(0,0,600,500);
539      this.ctx.beginPath();
540      this.ctx.globalAlpha = 0.1;
541      this.ctx.lineWidth = 10;
542      this.ctx.strokeStyle = '#0000ff';
543      this.ctx.moveTo(300, 0);
544      this.ctx.lineTo(300, 500);
545      this.ctx.stroke();
546      this.ctx.font = '35px';
547      this.ctx.globalAlpha = 1;
548      // 初始化 textBaseline
549      this.ctx.textBaseline = 'alphabetic';
550      // 设置textAlign
551      this.ctx.textAlign = 'left';
552      this.ctx.fillText('textAlign=left',300, 100);
553      this.ctx.textAlign = 'center';
554      this.ctx.fillText('textAlign=center',300, 250);
555      this.ctx.textAlign = 'right';
556      this.ctx.fillText('textAlign=right',300, 400);
557    }
558  }
559}
560```
561
562![zh-cn_image_0000001223064401](figures/zh-cn_image_0000001223064401.gif)
563
564> **说明:**
565> ltr布局模式下start和left一致,rtl布局模式下start和right一致·。
566
567
568## 添加图片
569
570创建图片对象后使用drawImage属性画出图片,给图片设置一些动画样式如scale(缩放)、translate(平移)或rotate(旋转)。
571
572
573```html
574<!-- xxx.hml -->
575<div class="container">
576  <div class="content">
577    <canvas ref="canvas0"></canvas>
578    <text onclick="change">change</text>
579    <canvas ref="canvas1"></canvas>
580    <text onclick="rotate">rotate</text>
581    <canvas ref="canvas2"></canvas>
582    <text onclick="scale">scale</text>
583    <canvas ref="canvas3"></canvas>
584    <text onclick="translate" style="width: 300px;">translate</text>
585    <canvas ref="canvas4"></canvas>
586    <text onclick="transform" style="width: 300px;">transform</text>
587    <canvas ref="canvas5"></canvas>
588    <text onclick="setTransform" style="width: 300px;">setTransform</text>
589    <canvas ref="canvas6"></canvas>
590  </div>
591</div>
592```
593
594
595```css
596/* xxx.css */
597.container{
598  width: 100%;
599  flex-direction: column;
600  background-color: #F1F3F5;
601  align-items: center;
602}
603canvas{
604  width: 600px;
605  height: 300px;
606  margin-bottom: 100px;
607  background-color: #fdfdfd;
608  border: 5px solid red;
609}
610.content{
611  width: 80%;
612  margin-top: 50px;
613  margin-bottom: 50px;
614  display: flex;
615  flex-wrap: wrap;
616  justify-content: space-around;
617}
618text{
619  font-size: 35px;
620  width: 200px;
621  height: 80px;
622  color: white;
623  border-radius: 20px;
624  text-align: center;
625  background-color: #6060e7;
626  margin-bottom: 30px;
627}
628```
629
630
631```js
632// xxx.js
633import promptAction from '@ohos.promptAction';
634export default {
635  data:{
636    compositeOperation: 'source-over'
637  },
638  onShow(){
639    let ctx = this.$refs.canvas0.getContext("2d");
640    // 创建图片对象
641    let img = new Image();
642    // 设置图片路径
643    img.src = 'common/images/2.png';
644    // 设置图片宽度
645    img.width= 150;
646    // 设置图片高度
647    img.height=150;
648    // 图片平铺容器
649    var pat = ctx.createPattern(img, 'repeat');ctx.fillStyle = pat;
650    ctx.fillRect(0, 0, 600, 300);
651  },
652  change(){
653    // 创建画布后得到画笔
654    let ctx = this.$refs.canvas1.getContext("2d");
655    ctx.clearRect(0,0,600,1000);
656    if(this.compositeOperation == "source-over"){
657      this.compositeOperation = "destination-over";
658    }else{
659      this.compositeOperation = "source-over";
660    }
661    ctx.globalCompositeOperation = this.compositeOperation;
662    let img = new Image();
663    img.src = 'common/images/2.png';
664    // 图片成功获取触发方法
665    img.onload = function() {
666      ctx.drawImage(img, 150, 20, 200, 200);
667    };
668    let img1 = new Image();
669    img1.src = 'common/images/3.png';
670    img1.onload = function() {
671      // 画上图片
672      ctx.drawImage(img1, 250, 80, 200, 200);
673    };
674    // 图片获取失败触发方法
675    img1.onerror = function() {
676      promptAction.showToast({message:"error",duration:2000})
677    };
678  },
679  rotate(){
680    let ctx = this.$refs.canvas2.getContext("2d");
681    ctx.clearRect(0,0,600,300);
682    // 旋转
683    ctx.rotate(10 * Math.PI / 180);
684    let img = new Image();
685    img.src = 'common/images/2.png';
686    img.onload = function() {
687      ctx.drawImage(img, 300, 0, 100, 100);
688    };
689  },
690  scale(){
691    let ctx = this.$refs.canvas3.getContext("2d");
692    ctx.clearRect(0,0,600,200);
693    // 缩放
694    ctx.scale(1.3,1.2);
695    let img = new Image();
696    img.src = 'common/images/2.png';
697    img.onload = function() {
698      ctx.drawImage(img, 0, 0, 50, 50);
699    };
700  },
701  translate(){
702    let ctx = this.$refs.canvas4.getContext("2d");
703    ctx.clearRect(0,0,600,300);
704    ctx.translate(10,0);
705    let img = new Image();
706    img.src = 'common/images/2.png';
707    img.onload = function() {
708      ctx.drawImage(img, 0, 50, 300, 200);
709    };
710  },
711  transform(){
712    let ctx = this.$refs.canvas5.getContext("2d");
713    ctx.clearRect(0,0,600,300);
714    ctx.transform(1.1, 0.1, 0.1, 1, 10, 0);
715    let img = new Image();
716    img.src = 'common/images/2.png';
717    img.onload = function() {
718      ctx.drawImage(img, 0, 50, 100, 100);
719     };
720  },
721  setTransform(){
722    let ctx = this.$refs.canvas6.getContext("2d");
723    ctx.clearRect(0,0,600,300);
724    ctx.setTransform(1.1, 0.1, 0.1, 1, 10, 0);
725    let img = new Image();
726    img.src = 'common/images/2.png';
727    img.onload = function() {
728      ctx.drawImage(img, 0, 50, 100, 100);
729    };
730  },
731}
732```
733
734![zh-cn_image_0000001218279600](figures/zh-cn_image_0000001218279600.gif)
735
736> **说明:**
737> - setTransfrom方法使用的参数和transform()方法相同,但setTransform()方法会重置现有的变换矩阵并创建新的变换矩阵。
738>
739> - 变换后的坐标计算方式(x和y为变换前坐标,x'和y'为变换后坐标):
740>   x' = scaleX \* x + skewY \* y + translateX
741>
742>   y' = skewX \* x + scaleY \* y + translateY
743
744
745## 添加方法
746
747save方法可对画笔样式进行存储,restore可对存储的画笔进行恢复。如下面的示例,先设置画笔为红色,在保存画笔后对画布进行清除并改变画笔为蓝色,当我们直接使用画笔时会画出一个蓝色矩形,对存储的画笔进行恢复后就可画出红色矩形。
748
749
750```html
751<!-- xxx.hml -->
752<div class="container">
753  <div class="content">
754    <canvas ref="canvas"></canvas>
755  </div>
756  <div class="content">
757    <text onclick="save">save</text>
758    <text onclick="clear">clear</text>
759    <text onclick="restore">restore</text>
760  </div>
761</div>
762```
763
764
765```css
766/* xxx.css */
767.container{
768  width: 100%;
769  height: 100%;
770  flex-direction: column;
771  background-color: #F1F3F5;
772  align-items: center;
773}
774canvas{
775  margin-top: 300px;
776  width: 600px;
777  height: 500px;
778  background-color: #fdfdfd;
779  border: 5px solid red;
780}
781.content{
782  width: 80%;
783  margin-top: 50px;
784  margin-bottom: 50px;
785  display: flex;
786  flex-wrap: wrap;
787  justify-content: space-around;
788}
789text{
790  width: 150px;
791  height: 80px;
792  color: white;
793  border-radius: 20px;
794  text-align: center;
795  background-color: #6060e7;
796  margin-bottom: 30px;
797}
798```
799
800
801```js
802// xxx.js
803import promptAction from '@ohos.promptAction';
804export default {
805  data:{
806    ctx: '',
807  },
808  onShow(){
809    this.ctx = this.$refs.canvas.getContext("2d");
810    this.ctx.fillStyle = "red"
811    this.ctx.fillRect(200, 150, 200, 200);
812  },
813  save(){
814    // 画笔储存
815    this.ctx.save();
816    promptAction.showToast({message:"save succeed"});
817  },
818  clear(){
819    this.ctx.clearRect(0,0,600,500);
820    // 该变画笔颜色
821    this.ctx.fillStyle = "#2133d2";
822  },
823  restore(){
824    this.ctx.beginPath();
825    // 画笔恢复
826    this.ctx.restore();
827    this.ctx.fillRect(200, 150, 200, 200);
828  },
829}
830```
831
832![zh-cn_image_0000001177624696](figures/zh-cn_image_0000001177624696.gif)
833