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