使用畫布繪制自定義圖形(Canvas)

2024-01-25 13:21 更新

Canvas提供畫布組件,用于自定義繪制圖形,開發(fā)者使用CanvasRenderingContext2D對(duì)象和OffscreenCanvasRenderingContext2D對(duì)象在Canvas組件上進(jìn)行繪制,繪制對(duì)象可以是基礎(chǔ)形狀、文本、圖片等。

使用畫布組件繪制自定義圖形

可以由以下三種形式在畫布繪制自定義圖形:

  • 使用CanvasRenderingContext2D對(duì)象在Canvas畫布上繪制。
    1. @Entry
    2. @Component
    3. struct CanvasExample1 {
    4. //用來配置CanvasRenderingContext2D對(duì)象的參數(shù),包括是否開啟抗鋸齒,true表明開啟抗鋸齒。
    5. private settings: RenderingContextSettings = new RenderingContextSettings(true)
    6. //用來創(chuàng)建CanvasRenderingContext2D對(duì)象,通過在canvas中調(diào)用CanvasRenderingContext2D對(duì)象來繪制。
    7. private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings)
    8. build() {
    9. Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
    10. //在canvas中調(diào)用CanvasRenderingContext2D對(duì)象。
    11. Canvas(this.context)
    12. .width('100%')
    13. .height('100%')
    14. .backgroundColor('#F5DC62')
    15. .onReady(() => {
    16. //可以在這里繪制內(nèi)容。
    17. this.context.strokeRect(50, 50, 200, 150);
    18. })
    19. }
    20. .width('100%')
    21. .height('100%')
    22. }
    23. }

  • 離屏繪制是指將需要繪制的內(nèi)容先繪制在緩存區(qū),再將其轉(zhuǎn)換成圖片,一次性繪制到Canvas上,加快了繪制速度。過程為:
    1. 通過transferToImageBitmap方法將離屏畫布最近渲染的圖像創(chuàng)建為一個(gè)ImageBitmap對(duì)象。
    2. 通過CanvasRenderingContext2D對(duì)象的transferFromImageBitmap方法顯示給定的ImageBitmap對(duì)象。
    具體使用參考OffscreenCanvasRenderingContext2D對(duì)象
    1. @Entry
    2. @Component
    3. struct CanvasExample2 {
    4. //用來配置CanvasRenderingContext2D對(duì)象和OffscreenCanvasRenderingContext2D對(duì)象的參數(shù),包括是否開啟抗鋸齒。true表明開啟抗鋸齒
    5. private settings: RenderingContextSettings = new RenderingContextSettings(true)
    6. private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings)
    7. //用來創(chuàng)建OffscreenCanvasRenderingContext2D對(duì)象,width為離屏畫布的寬度,height為離屏畫布的高度。通過在canvas中調(diào)用OffscreenCanvasRenderingContext2D對(duì)象來繪制。
    8. private offContext: OffscreenCanvasRenderingContext2D = new OffscreenCanvasRenderingContext2D(600, 600, this.settings)
    9. build() {
    10. Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
    11. Canvas(this.context)
    12. .width('100%')
    13. .height('100%')
    14. .backgroundColor('#F5DC62')
    15. .onReady(() =>{
    16. //可以在這里繪制內(nèi)容
    17. this.offContext.strokeRect(50, 50, 200, 150);
    18. //將離屏繪值渲染的圖像在普通畫布上顯示
    19. let image = this.offContext.transferToImageBitmap();
    20. this.context.transferFromImageBitmap(image);
    21. })
    22. }
    23. .width('100%')
    24. .height('100%')
    25. }
    26. }

    說明

    在畫布組件中,通過CanvasRenderingContext2D對(duì)象和OffscreenCanvasRenderingContext2D對(duì)象在Canvas組件上進(jìn)行繪制時(shí)調(diào)用的接口相同,另接口參數(shù)如無特別說明,單位均為vp。

  • 在Canvas上加載Lottie動(dòng)畫時(shí),需要先按照如下方式下載Lottie。
    1. import lottie from '@ohos/lottie'

    具體接口和示例請(qǐng)參考Lottie。

初始化畫布組件

onReady(event: () => void)是Canvas組件初始化完成時(shí)的事件回調(diào),調(diào)用該事件后,可獲取Canvas組件的確定寬高,進(jìn)一步使用CanvasRenderingContext2D對(duì)象和OffscreenCanvasRenderingContext2D對(duì)象調(diào)用相關(guān)API進(jìn)行圖形繪制。

  1. Canvas(this.context)
  2. .width('100%')
  3. .height('100%')
  4. .backgroundColor('#F5DC62')
  5. .onReady(() => {
  6. this.context.fillStyle = '#0097D4';
  7. this.context.fillRect(50, 50, 100, 100);
  8. })

畫布組件繪制方式

Canvas組件生命周期接口onReady()調(diào)用之后,開發(fā)者可以直接使用canvas組件進(jìn)行繪制?;蛘呖梢悦撾xCanvas組件和onready生命周期,單獨(dú)定義Path2d對(duì)象構(gòu)造理想的路徑,并在onready調(diào)用之后使用Canvas組件進(jìn)行繪制。

  • 通過CanvasRenderingContext2D對(duì)象和OffscreenCanvasRenderingContext2D對(duì)象直接調(diào)用相關(guān)API進(jìn)行繪制。
    1. Canvas(this.context)
    2. .width('100%')
    3. .height('100%')
    4. .backgroundColor('#F5DC62')
    5. .onReady(() =>{
    6. this.context.beginPath();
    7. this.context.moveTo(50, 50);
    8. this.context.lineTo(280, 160);
    9. this.context.stroke();
    10. })

  • 先單獨(dú)定義path2d對(duì)象構(gòu)造理想的路徑,再通過調(diào)用CanvasRenderingContext2D對(duì)象和OffscreenCanvasRenderingContext2D對(duì)象的stroke接口或者fill接口進(jìn)行繪制,具體使用可以參考Path2D對(duì)象。
    1. Canvas(this.context)
    2. .width('100%')
    3. .height('100%')
    4. .backgroundColor('#F5DC62')
    5. .onReady(() =>{
    6. let region = new Path2D();
    7. region.arc(100, 75, 50, 0, 6.28);
    8. this.context.stroke(region);
    9. })

畫布組件常用方法

OffscreenCanvasRenderingContext2D對(duì)象和CanvasRenderingContext2D對(duì)象提供了大量的屬性和方法,可以用來繪制文本、圖形,處理像素等,是Canvas組件的核心。常用接口有fill(對(duì)封閉路徑進(jìn)行填充)、clip(設(shè)置當(dāng)前路徑為剪切路徑)、stroke(進(jìn)行邊框繪制操作)等等,同時(shí)提供了fillStyle(指定繪制的填充色)、globalAlpha(設(shè)置透明度)strokeStyle(設(shè)置描邊的顏色)等屬性修改繪制內(nèi)容的樣式。將通過以下幾個(gè)方面簡(jiǎn)單介紹畫布組件常見使用方法:

  • 基礎(chǔ)形狀繪制。
    可以通過arc(繪制弧線路徑)、 ellipse繪制一個(gè)橢圓)、rect(創(chuàng)建矩形路徑)等接口繪制基礎(chǔ)形狀。
    1. Canvas(this.context)
    2. .width('100%')
    3. .height('100%')
    4. .backgroundColor('#F5DC62')
    5. .onReady(() =>{
    6. //繪制矩形
    7. this.context.beginPath();
    8. this.context.rect(100, 50, 100, 100);
    9. this.context.stroke();
    10. //繪制圓形
    11. this.context.beginPath();
    12. this.context.arc(150, 250, 50, 0, 6.28);
    13. this.context.stroke();
    14. //繪制橢圓
    15. this.context.beginPath();
    16. this.context.ellipse(150, 450, 50, 100, Math.PI * 0.25, Math.PI * 0, Math.PI * 2);
    17. this.context.stroke();
    18. })

  • 文本繪制。
    可以通過fillText(繪制填充類文本)、strokeText繪制描邊類文本)等接口進(jìn)行文本繪制。
    1. Canvas(this.context)
    2. .width('100%')
    3. .height('100%')
    4. .backgroundColor('#F5DC62')
    5. .onReady(() =>{
    6. //繪制填充類文本
    7. this.context.font = '50px sans-serif';
    8. this.context.fillText("Hello World!", 50, 100);
    9. //繪制描邊類文本
    10. this.context.font = '55px sans-serif';
    11. this.context.strokeText("Hello World!", 50, 150);
    12. })

  • 繪制圖片和圖像像素信息處理
    可以通過drawImage圖像繪制)、putImageData使用ImageData數(shù)據(jù)填充新的矩形區(qū)域)等接口繪制圖片,通過createImageData創(chuàng)建新的ImageData 對(duì)象)、getPixelMap以當(dāng)前canvas指定區(qū)域內(nèi)的像素創(chuàng)建PixelMap對(duì)象)、getImageData(以當(dāng)前canvas指定區(qū)域內(nèi)的像素創(chuàng)建ImageData對(duì)象)等接口進(jìn)行圖像像素信息處理。
    1. @Entry
    2. @Component
    3. struct GetImageData {
    4. private settings: RenderingContextSettings = new RenderingContextSettings(true)
    5. private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings)
    6. private offContext: OffscreenCanvasRenderingContext2D = new OffscreenCanvasRenderingContext2D(600, 600, this.settings)
    7. private img:ImageBitmap = new ImageBitmap("/common/images/1234.png")
    8. build() {
    9. Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
    10. Canvas(this.context)
    11. .width('100%')
    12. .height('100%')
    13. .backgroundColor('#F5DC62')
    14. .onReady(() =>{
    15. // 使用drawImage接口將圖片畫在(0,0)為起點(diǎn),寬高130的區(qū)域
    16. this.offContext.drawImage(this.img,0,0,130,130);
    17. // 使用getImageData接口,獲得canvas組件區(qū)域中,(50,50)為起點(diǎn),寬高130范圍內(nèi)的繪制內(nèi)容
    18. let imagedata = this.offContext.getImageData(50,50,130,130);
    19. // 使用putImageData接口將得到的ImageData畫在起點(diǎn)為(150, 150)的區(qū)域中
    20. this.offContext.putImageData(imagedata,150,150);
    21. // 將離屏繪制的內(nèi)容畫到canvas組件上
    22. let image = this.offContext.transferToImageBitmap();
    23. this.context.transferFromImageBitmap(image);
    24. })
    25. }
    26. .width('100%')
    27. .height('100%')
    28. }
    29. }

  • 其他方法。

    Canvas中還提供其他類型的方法。漸變(CanvasGradient對(duì)象)相關(guān)的方法:createLinearGradient(創(chuàng)建一個(gè)線性漸變色)、createRadialGradient(創(chuàng)建一個(gè)徑向漸變色)等。

    1. Canvas(this.context)
    2. .width('100%')
    3. .height('100%')
    4. .backgroundColor('#F5DC62')
    5. .onReady(() =>{
    6. //創(chuàng)建一個(gè)徑向漸變色的CanvasGradient對(duì)象
    7. let grad = this.context.createRadialGradient(200,200,50, 200,200,200)
    8. //為CanvasGradient對(duì)象設(shè)置漸變斷點(diǎn)值,包括偏移和顏色
    9. grad.addColorStop(0.0, '#E87361');
    10. grad.addColorStop(0.5, '#FFFFF0');
    11. grad.addColorStop(1.0, '#BDDB69');
    12. //用CanvasGradient對(duì)象填充矩形
    13. this.context.fillStyle = grad;
    14. this.context.fillRect(0, 0, 400, 400);
    15. })

場(chǎng)景示例

  • 規(guī)則基礎(chǔ)形狀繪制:
    1. @Entry
    2. @Component
    3. struct ClearRect {
    4. private settings: RenderingContextSettings = new RenderingContextSettings(true);
    5. private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings);
    6. build() {
    7. Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
    8. Canvas(this.context)
    9. .width('100%')
    10. .height('100%')
    11. .backgroundColor('#F5DC62')
    12. .onReady(() =>{
    13. // 設(shè)定填充樣式,填充顏色設(shè)為藍(lán)色
    14. this.context.fillStyle = '#0097D4';
    15. // 以(50, 50)為左上頂點(diǎn),畫一個(gè)寬高200的矩形
    16. this.context.fillRect(50,50,200,200);
    17. // 以(70, 70)為左上頂點(diǎn),清除寬150高100的區(qū)域
    18. this.context.clearRect(70,70,150,100);
    19. })
    20. }
    21. .width('100%')
    22. .height('100%')
    23. }
    24. }

  • 不規(guī)則圖形繪制。
    1. @Entry
    2. @Component
    3. struct Path2d {
    4. private settings: RenderingContextSettings = new RenderingContextSettings(true);
    5. private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings);
    6. build() {
    7. Row() {
    8. Column() {
    9. Canvas(this.context)
    10. .width('100%')
    11. .height('100%')
    12. .backgroundColor('#F5DC62')
    13. .onReady(() =>{
    14. // 使用Path2D的接口構(gòu)造一個(gè)五邊形
    15. let path = new Path2D();
    16. path.moveTo(150, 50);
    17. path.lineTo(50, 150);
    18. path.lineTo(100, 250);
    19. path.lineTo(200, 250);
    20. path.lineTo(250, 150);
    21. path.closePath();
    22. // 設(shè)定填充色為藍(lán)色
    23. this.context.fillStyle = '#0097D4';
    24. // 使用填充的方式,將Path2D描述的五邊形繪制在canvas組件內(nèi)部
    25. this.context.fill(path);
    26. })
    27. }
    28. .width('100%')
    29. }
    30. .height('100%')
    31. }
    32. }

以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)