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 .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 given **ImageBitmap** object. 46 47 For details, see [OffscreenCanvasRenderingContext2D](../reference/apis-arkui/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 OffscreenCanvas object. width indicates the width of the offscreen canvas, and height indicates the height of the offscreen canvas. 57 private offCanvas: OffscreenCanvas = new OffscreenCanvas(600, 600) 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 let offContext = this.offCanvas.getContext("2d", this.settings) 67 // You can draw content here. 68 offContext.strokeRect(50, 50, 200, 150); 69 // Display the image rendered by the offscreen drawing value on the common canvas. 70 let image = this.offCanvas.transferToImageBitmap(); 71 this.context.transferFromImageBitmap(image); 72 }) 73 } 74 .width('100%') 75 .height('100%') 76 } 77 } 78 ``` 79 80 .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](https://gitee.com/openharmony-tpc/lottieETS). 93 94 95## Initializing the Canvas Component 96 97**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. 98 99```ts 100Canvas(this.context) 101 .width('100%') 102 .height('100%') 103 .backgroundColor('#F5DC62') 104 .onReady(() => { 105 this.context.fillStyle = '#0097D4'; 106 this.context.fillRect(50, 50, 100, 100); 107 }) 108``` 109 110.jpg) 111 112 113## Canvas Component Drawing Modes 114 115After **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. 116 117- After the **onReady()** callback of the **Canvas** component is invoked, use the **CanvasRenderingContext2D** and **OffscreenCanvasRenderingContext2D** objects to call related APIs for drawing. 118 119 ```ts 120 Canvas(this.context) 121 .width('100%') 122 .height('100%') 123 .backgroundColor('#F5DC62') 124 .onReady(() => { 125 this.context.beginPath(); 126 this.context.moveTo(50, 50); 127 this.context.lineTo(280, 160); 128 this.context.stroke(); 129 }) 130 ``` 131 132 .jpg) 133 134- 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). 135 136 ```ts 137 Canvas(this.context) 138 .width('100%') 139 .height('100%') 140 .backgroundColor('#F5DC62') 141 .onReady(() => { 142 let region = new Path2D(); 143 region.arc(100, 75, 50, 0, 6.28); 144 this.context.stroke(region); 145 }) 146 ``` 147 148 .jpg) 149 150 151## Common Usage of the Canvas Component 152 153**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. 154 155- Draw a basic shape. 156 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). 157 158 ```ts 159 Canvas(this.context) 160 .width('100%') 161 .height('100%') 162 .backgroundColor('#F5DC62') 163 .onReady(() => { 164 // Draw a rectangle. 165 this.context.beginPath(); 166 this.context.rect(100, 50, 100, 100); 167 this.context.stroke(); 168 // Draw a circle on the canvas. 169 this.context.beginPath(); 170 this.context.arc(150, 250, 50, 0, 6.28); 171 this.context.stroke(); 172 // Draw an oval on the canvas. 173 this.context.beginPath(); 174 this.context.ellipse(150, 450, 50, 100, Math.PI * 0.25, Math.PI * 0, Math.PI * 2); 175 this.context.stroke(); 176 }) 177 ``` 178 179 .jpg) 180 181- Draw text. 182 183 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. In the example, the **font** attribute is set to a bold, 50 px high "sans-serif" font. The **fillText** API is used to draw the text "Hello World!" at the position (50, 100). In addition, the **strokeText** API is used to draw the outline of the text "Hello World!" at the position (50, 150) with a red stroke style and a line width of 2. 184 185 ```ts 186 Canvas(this.context) 187 .width('100%') 188 .height('100%') 189 .backgroundColor('#F5DC62') 190 .onReady(() => { 191 // Draw filled text on the canvas. 192 this.context.font = '50px bolder sans-serif'; 193 this.context.fillText("Hello World!", 50, 100); 194 // Draw a text stroke on the canvas. 195 this.context.strokeStyle = "#ff0000" 196 this.context.lineWidth = 2 197 this.context.font = '50px bolder sans-serif'; 198 this.context.strokeText("Hello World!", 50, 150); 199 }) 200 ``` 201 202 .jpg) 203 204- Draw text with a custom font. 205 206 You can use the [font](../reference/apis-arkui/arkui-ts/ts-canvasrenderingcontext2d.md#font) API to load a custom font, and then use the [fillText](../reference/apis-arkui/arkui-ts/ts-canvasrenderingcontext2d.md#filltext) and [strokeText](../reference/apis-arkui/arkui-ts/ts-canvasrenderingcontext2d.md#stroketext) APIs to draw text. 207 208 ```ts 209 Canvas(this.context) 210 .width('100%') 211 .height('100%') 212 .backgroundColor('#F5DC62') 213 .onReady(() => { 214 // Load a custom font. 215 this.context.font = '30vp customFont' 216 this.context.fillText("Hello World!", 20, 50) 217 this.context.strokeText("Hello World!", 20, 100) 218 }) 219 ``` 220 221  222 223- Draw images and processes image pixel information. 224 225 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). 226 227 ```ts 228 @Entry 229 @Component 230 struct GetImageData { 231 private settings: RenderingContextSettings = new RenderingContextSettings(true) 232 private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings) 233 private offCanvas: OffscreenCanvas = new OffscreenCanvas(600, 600) 234 private img: ImageBitmap = new ImageBitmap("/common/images/1234.png") 235 236 build() { 237 Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { 238 Canvas(this.context) 239 .width('100%') 240 .height('100%') 241 .backgroundColor('#F5DC62') 242 .onReady(() => { 243 let offContext = this.offCanvas.getContext("2d", this.settings) 244 // Use the drawImage API to draw an image in the area with the width and height of 130 starting from (0, 0). 245 offContext.drawImage(this.img, 0, 0, 130, 130); 246 // Use the getImageData API to obtain the image data with the width and height of 130 starting from (50, 50). 247 let imagedata = offContext.getImageData(50, 50, 130, 130); 248 // Use the putImageData API to draw the obtained image data in the area starting from (150, 150). 249 offContext.putImageData(imagedata, 150, 150); 250 // Draw the offscreen drawing content to the canvas. 251 let image = this.offCanvas.transferToImageBitmap(); 252 this.context.transferFromImageBitmap(image); 253 }) 254 } 255 .width('100%') 256 .height('100%') 257 } 258 } 259 ``` 260 261  262 263- Other usage 264 265 **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. 266 267 ```ts 268 Canvas(this.context) 269 .width('100%') 270 .height('100%') 271 .backgroundColor('#F5DC62') 272 .onReady(() => { 273 // Create a CanvasGradient object with radial gradient colors. 274 let grad = this.context.createRadialGradient(200, 200, 50, 200, 200, 200) 275 // Set the gradient color stop for the CanvasGradient object, including the offset and colors. 276 grad.addColorStop(0.0, '#E87361'); 277 grad.addColorStop(0.5, '#FFFFF0'); 278 grad.addColorStop(1.0, '#BDDB69'); 279 // Fill the rectangle with the CanvasGradient object. 280 this.context.fillStyle = grad; 281 this.context.fillRect(0, 0, 400, 400); 282 }) 283 ``` 284 285 .jpg) 286 287 288## Example Scenario 289 290- Draw a basic shape. 291 292 ```ts 293 @Entry 294 @Component 295 struct ClearRect { 296 private settings: RenderingContextSettings = new RenderingContextSettings(true); 297 private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings); 298 299 build() { 300 Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { 301 Canvas(this.context) 302 .width('100%') 303 .height('100%') 304 .backgroundColor('#F5DC62') 305 .onReady(() => { 306 // Set the fill color to blue. 307 this.context.fillStyle = '#0097D4'; 308 // Take (50, 50) as the upper left corner and draw a rectangle with the width and height of 200. 309 this.context.fillRect(50, 50, 200, 200); 310 // Use (70, 70) as the upper left corner and clear the area with the width of 150 and height of 100. 311 this.context.clearRect(70, 70, 150, 100); 312 }) 313 } 314 .width('100%') 315 .height('100%') 316 } 317 } 318 ``` 319 320 .jpg) 321 322- Draw an irregular shape. 323 324 ```ts 325 @Entry 326 @Component 327 struct Path2d { 328 private settings: RenderingContextSettings = new RenderingContextSettings(true); 329 private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings); 330 331 build() { 332 Row() { 333 Column() { 334 Canvas(this.context) 335 .width('100%') 336 .height('100%') 337 .backgroundColor('#F5DC62') 338 .onReady(() => { 339 // Use the Path2D API to create a pentagon. 340 let path = new Path2D(); 341 path.moveTo(150, 50); 342 path.lineTo(50, 150); 343 path.lineTo(100, 250); 344 path.lineTo(200, 250); 345 path.lineTo(250, 150); 346 path.closePath(); 347 // Set the fill color to blue. 348 this.context.fillStyle = '#0097D4'; 349 // Draw the pentagon described by Path2D in the canvas in fill mode. 350 this.context.fill(path); 351 }) 352 } 353 .width('100%') 354 } 355 .height('100%') 356 } 357 } 358 ``` 359 360  361