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