• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Drawing Custom Graphics Using the Canvas
2
3
4**Canvas** provides a canvas component for drawing custom graphics. You can use the **CanvasRenderingContext2D** and **OffscreenCanvasRenderingContext2D** objects to draw graphics on the **Canvas** component. The drawing objects can be basic shapes, text, and images.
5
6
7## Drawing Custom Graphics on the Canvas
8
9You can draw custom graphics on the canvas in any of the following ways:
10
11
12- Use [CanvasRenderingContext2D](../reference/arkui-ts/ts-canvasrenderingcontext2d.md).
13
14  ```ts
15  @Entry
16  @Component
17  struct CanvasExample1 {
18  // Configure the parameters of the CanvasRenderingContext2D object, including whether to enable anti-aliasing. The value true indicates that anti-aliasing is enabled.
19   private settings: RenderingContextSettings = new RenderingContextSettings(true)
20  // Create a CanvasRenderingContext2D object by calling CanvasRenderingContext2D object in Canvas.
21  private context: CanvasRenderingContext2D= new CanvasRenderingContext2D(this.settings)
22    build() {
23  Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
24        // Invoke the CanvasRenderingContext2D object in Canvas.
25        Canvas(this.context)
26          .width('100%')
27          .height('100%')
28          .backgroundColor('#F5DC62')
29          .onReady(() =>{
30           // You can draw content here.
31            this.context.strokeRect(50, 50, 200, 150);
32        })
33      }
34      .width('100%')
35      .height('100%')
36    }
37  }
38
39  ```
40
41  ![2023022793003(1)](figures/2023022793003(1).jpg)
42
43- Drawing offscreen onto a canvas is a process where content to draw onto the canvas is first drawn in the buffer, and then converted into a picture, and finally the picture is drawn on the canvas. This process increases the drawing efficiency. Specifically, the implementation is as follows:
44  1. Use the **transferToImageBitmap** API to create an **ImageBitmap** object for the image that is recently rendered off the screen canvas.
45  2. Use the **transferFromImageBitmap** API of the **CanvasRenderingContext2D** object to display the created **ImageBitmap** object.
46
47    For details, see [OffscreenCanvasRenderingContext2D](../reference/arkui-ts/ts-offscreencanvasrenderingcontext2d.md).
48
49  ```ts
50  @Entry
51  @Component
52  struct CanvasExample2 {
53  // Configure the parameters of the CanvasRenderingContext2D and OffscreenCanvasRenderingContext2D objects, including whether to enable anti-aliasing. The value true indicates that anti-aliasing is enabled.
54    private settings: RenderingContextSettings = new RenderingContextSettings(true)
55    private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings)
56  // Create an OffscreenCanvasRenderingContext2D object. width indicates the width of the offscreen canvas, and height indicates the height of the offscreen canvas.
57    private offContext: OffscreenCanvasRenderingContext2D = new OffscreenCanvasRenderingContext2D(600, 600, this.settings)
58
59    build() {
60      Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
61        Canvas(this.context)
62          .width('100%')
63          .height('100%')
64          .backgroundColor('#F5DC62')
65          .onReady(() =>{
66            // You can draw content here.
67            this.offContext.strokeRect(50, 50, 200, 150);
68            // Display the image rendered by the offscreen drawing value on the common canvas.
69            let image = this.offContext.transferToImageBitmap();
70            this.context.transferFromImageBitmap(image);
71          })
72      }
73      .width('100%')
74      .height('100%')
75    }
76  }
77
78  ```
79
80  ![2023022793003(1)](figures/2023022793003(1).jpg)
81
82  >**NOTE**
83  >
84  >The APIs called for drawing on the canvas through the **CanvasRenderingContext2D** and **OffscreenCanvasRenderingContext2D** objects are the same. Unless otherwise specified, the value unit of the parameters in these APIs is vp.
85
86- Before loading the Lottie animation on the canvas, download the Lottie as follows:
87
88  ```ts
89  import lottie from '@ohos/lottie'
90  ```
91
92  For details about the APIs, see [Lottie](../reference/arkui-ts/ts-components-canvas-lottie.md).
93
94  >**NOTE**
95  >
96  >Before using Lottie for the first time, run the **ohpm install \@ohos/lottieETS** command in the Terminal window to download Lottie.
97
98
99## Initializing the Canvas Component
100
101**onReady(event: () => void)** is the event callback when the **Canvas** component initialization is complete. After this event is called, the determined width and height of the **Canvas** component can be obtained. The **CanvasRenderingContext2D** and **OffscreenCanvasRenderingContext2D** objects can then be used to call related APIs to draw graphics.
102
103```ts
104Canvas(this.context)
105  .width('100%')
106  .height('100%')
107  .backgroundColor('#F5DC62')
108  .onReady(() => {
109    this.context.fillStyle = '#0097D4';
110    this.context.fillRect(50, 50, 100, 100);
111  })
112
113```
114
115![2023022793350(1)](figures/2023022793350(1).jpg)
116
117
118## Canvas Component Drawing Modes
119
120Two modes are available for drawing with the **Canvas** component:
121
122- After the **onReady()** callback of the **Canvas** component is invoked, use the **CanvasRenderingContext2D** and **OffscreenCanvasRenderingContext2D** objects to call related APIs for drawing.
123
124  ```ts
125  Canvas(this.context)
126    .width('100%')
127    .height('100%')
128    .backgroundColor('#F5DC62')
129    .onReady(() =>{
130      this.context.beginPath();
131      this.context.moveTo(50, 50);
132      this.context.lineTo(280, 160);
133      this.context.stroke();
134     })
135  ```
136
137  ![2023022793719(1)](figures/2023022793719(1).jpg)
138
139- Define an individual **path2d** object to build an ideal path, and then call the **stroke** or **fill** API of the **CanvasRenderingContext2D** and **OffscreenCanvasRenderingContext2D** objects to draw the path. For details, see [Path2D](../reference/arkui-ts/ts-components-canvas-path2d.md).
140
141  ```ts
142  Canvas(this.context)
143    .width('100%')
144    .height('100%')
145    .backgroundColor('#F5DC62')
146    .onReady(() =>{
147       let region = new Path2D();
148       region.arc(100, 75, 50, 0, 6.28);
149       this.context.stroke(region);
150    })
151  ```
152
153  ![2023022794031(1)](figures/2023022794031(1).jpg)
154
155
156## Common Usage of the Canvas Component
157
158**OffscreenCanvasRenderingContext2D** and **CanvasRenderingContext2D** provide a large number of attributes and methods, which can be used to draw text and graphics and process pixels. They are the core of the **Canvas** component. Common APIs include [fill](../reference/arkui-ts/ts-canvasrenderingcontext2d.md#fill), [clip](../reference/arkui-ts/ts-canvasrenderingcontext2d.md#clip), and [stroke](../reference/arkui-ts/ts-canvasrenderingcontext2d.md#stroke). In addition, [fillStyle](../reference/arkui-ts/ts-canvasrenderingcontext2d.md#fillstyle), [globalAlpha](../reference/arkui-ts/ts-canvasrenderingcontext2d.md#globalalpha), [strokeStyle](../reference/arkui-ts/ts-canvasrenderingcontext2d.md#strokestyle), and more attributes are provided to spruce up the graphics. This topic describes typical usage of the canvas.
159
160- Draw a basic shape.
161
162
163You can draw a basic shape by calling APIs such as [arc](../reference/arkui-ts/ts-canvasrenderingcontext2d.md#arc), [ellipse](../reference/arkui-ts/ts-canvasrenderingcontext2d.md#ellipse), and [rect](../reference/arkui-ts/ts-canvasrenderingcontext2d.md#rect).
164
165  ```ts
166  Canvas(this.context)
167    .width('100%')
168    .height('100%')
169    .backgroundColor('#F5DC62')
170    .onReady(() =>{
171       // Draw a rectangle.
172       this.context.beginPath();
173       this.context.rect(100, 50, 100, 100);
174       this.context.stroke();
175       // Draw a circle on the canvas.
176       this.context.beginPath();
177       this.context.arc(150, 250, 50, 0, 6.28);
178       this.context.stroke();
179       // Draw an oval on the canvas.
180       this.context.beginPath();
181       this.context.ellipse(150, 450, 50, 100, Math.PI * 0.25, Math.PI * 0, Math.PI * 2);
182       this.context.stroke();
183  })
184
185  ```
186
187![2023022794521(1)](figures/2023022794521(1).jpg)
188
189- Draw text.
190
191  You can use APIs such as [fillText](../reference/arkui-ts/ts-canvasrenderingcontext2d.md#filltext) and [strokeText](../reference/arkui-ts/ts-canvasrenderingcontext2d.md#stroketext) to draw text.
192
193  ```ts
194  Canvas(this.context)
195    .width('100%')
196    .height('100%')
197    .backgroundColor('#F5DC62')
198    .onReady(() =>{
199       // Draw filled text on the canvas.
200       this.context.font = '50px sans-serif';
201       this.context.fillText("Hello World!", 50, 100);
202       // Draw a text stroke on the canvas.
203       this.context.font = '55px sans-serif';
204       this.context.strokeText("Hello World!", 50, 150);
205    })
206  ```
207
208  ![2023022795105(1)](figures/2023022795105(1).jpg)
209
210- Draw images and processes image pixel information.
211
212  You can draw an image by calling APIs such as [drawImage](../reference/arkui-ts/ts-canvasrenderingcontext2d.md#drawimage) and [putImageData](../reference/arkui-ts/ts-canvasrenderingcontext2d.md#putimagedata). You can also process image pixel information by calling APIs such as [createImageData](../reference/arkui-ts/ts-canvasrenderingcontext2d.md#createimagedata), [getPixelMap](../reference/arkui-ts/ts-canvasrenderingcontext2d.md#getpixelmap), and [getImageData](../reference/arkui-ts/ts-canvasrenderingcontext2d.md#getimagedata).
213
214  ```ts
215  @Entry
216  @Component
217  struct GetImageData {
218   private settings: RenderingContextSettings = new RenderingContextSettings(true)
219   private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings)
220   private offContext: OffscreenCanvasRenderingContext2D = new OffscreenCanvasRenderingContext2D(600, 600, this.settings)
221   private img:ImageBitmap = new ImageBitmap("/common/images/1234.png")
222
223    build() {
224      Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
225        Canvas(this.context)
226          .width('100%')
227          .height('100%')
228          .backgroundColor('#F5DC62')
229          .onReady(() =>{
230            // Use the drawImage API to draw an image in the area with the width and height of 130 starting from (0, 0).
231            this.offContext.drawImage(this.img,0,0,130,130);
232            // Use the getImageData API to obtain the image data with the width and height of 130 starting from (50, 50).
233            let imagedata = this.offContext.getImageData(50,50,130,130);
234            // Use the putImageData API to draw the obtained image data in the area starting from (150, 150).
235            this.offContext.putImageData(imagedata,150,150);
236            // Draw the offscreen drawing content to the canvas.
237            let image = this.offContext.transferToImageBitmap();
238            this.context.transferFromImageBitmap(image);
239          })
240      }
241      .width('100%')
242      .height('100%')
243    }
244  }
245  ```
246
247  ![drawimage](figures/drawimage.PNG)
248
249- Other usage
250
251  **Canvas** also provides other usage. For example, regarding [CanvasGradient](../reference/arkui-ts/ts-components-canvas-canvasgradient.md), you can create a linear gradient with [createLinearGradient](../reference/arkui-ts/ts-canvasrenderingcontext2d.md#createlineargradient) or create a radial gradient with [createRadialGradient](../reference/arkui-ts/ts-canvasrenderingcontext2d.md#createradialgradient), among others.
252
253  ```ts
254  Canvas(this.context)
255    .width('100%')
256    .height('100%')
257    .backgroundColor('#F5DC62')
258    .onReady(() =>{
259       // Create a CanvasGradient object with radial gradient colors.
260       let grad = this.context.createRadialGradient(200,200,50, 200,200,200)
261       // Set the gradient color stop for the CanvasGradient object, including the offset and colors.
262       grad.addColorStop(0.0, '#E87361');
263       grad.addColorStop(0.5, '#FFFFF0');
264       grad.addColorStop(1.0, '#BDDB69');
265       // Fill the rectangle with the CanvasGradient object.
266       this.context.fillStyle = grad;
267       this.context.fillRect(0, 0, 400, 400);
268    })
269  ```
270
271  ![2023022700701(1)](figures/2023022700701(1).jpg)
272
273
274## Example Scenario
275
276- Draw a basic shape.
277
278  ```ts
279  @Entry
280  @Component
281  struct ClearRect {
282   private settings: RenderingContextSettings = new RenderingContextSettings(true);
283   private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings);
284
285    build() {
286      Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
287        Canvas(this.context)
288          .width('100%')
289          .height('100%')
290          .backgroundColor('#F5DC62')
291          .onReady(() =>{
292            // Set the fill color to blue.
293            this.context.fillStyle = '#0097D4';
294            // Take (50, 50) as the upper left corner and draw a rectangle with the width and height of 200.
295            this.context.fillRect(50,50,200,200);
296            // Use (70, 70) as the upper left corner and clear the area with the width of 150 and height of 100.
297            this.context.clearRect(70,70,150,100);
298        })
299      }
300      .width('100%')
301      .height('100%')
302    }
303  }
304
305  ```
306
307  ![2023022701120(1)](figures/2023022701120(1).jpg)
308
309- Draw an irregular shape.
310
311  ```ts
312  @Entry
313  @Component
314  struct Path2d {
315    private settings: RenderingContextSettings = new RenderingContextSettings(true);
316    private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings);
317
318    build() {
319      Row() {
320        Column() {
321          Canvas(this.context)
322            .width('100%')
323            .height('100%')
324            .backgroundColor('#F5DC62')
325            .onReady(() =>{
326              // Use the Path2D API to create a pentagon.
327              let path = new Path2D();
328              path.moveTo(150, 50);
329              path.lineTo(50, 150);
330              path.lineTo(100, 250);
331              path.lineTo(200, 250);
332              path.lineTo(250, 150);
333              path.closePath();
334              // Set the fill color to blue.
335              this.context.fillStyle = '#0097D4';
336              // Draw the pentagon described by Path2D in the canvas in fill mode.
337              this.context.fill(path);
338            })
339        }
340        .width('100%')
341      }
342      .height('100%')
343    }
344  }
345  ```
346
347  ![2023032422159](figures/2023032422159.jpg)
348
349