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