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