1# Drawing Custom Graphics on 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 a Custom Chart Using the Canvas 8 9You can draw a custom chart 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 the 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 the 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. The process 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/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 the 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 unit of the API parameters 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 120After the **Canvas** component lifecycle callback **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 called. 121 122- The **CanvasRenderingContext2D** and **OffscreenCanvasRenderingContext2D** objects are used to directly 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 the **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), and [strokeStyle](../reference/arkui-ts/ts-canvasrenderingcontext2d.md#strokestyle) and more attributes are provided. This topic describes typical usage of the canvas. 159 160- Draw a basic shape. 161 You 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). 162 163 ```ts 164 Canvas(this.context) 165 .width('100%') 166 .height('100%') 167 .backgroundColor('#F5DC62') 168 .onReady(() =>{ 169 // Draw a rectangle. 170 this.context.beginPath(); 171 this.context.rect(100, 50, 100, 100); 172 this.context.stroke(); 173 // Draw a circle on the canvas. 174 this.context.beginPath(); 175 this.context.arc(150, 250, 50, 0, 6.28); 176 this.context.stroke(); 177 // Draw an oval on the canvas. 178 this.context.beginPath(); 179 this.context.ellipse(150, 450, 50, 100, Math.PI * 0.25, Math.PI * 0, Math.PI * 2); 180 this.context.stroke(); 181 }) 182 183 ``` 184 185 ![2023022794521(1)](figures/2023022794521(1).jpg) 186 187- Draw text. 188 189 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. 190 191 ```ts 192 Canvas(this.context) 193 .width('100%') 194 .height('100%') 195 .backgroundColor('#F5DC62') 196 .onReady(() =>{ 197 // Draw filled text on the canvas. 198 this.context.font = '50px sans-serif'; 199 this.context.fillText("Hello World!", 50, 100); 200 // Draw a text stroke on the canvas. 201 this.context.font = '55px sans-serif'; 202 this.context.strokeText("Hello World!", 50, 150); 203 }) 204 ``` 205 206 ![2023022795105(1)](figures/2023022795105(1).jpg) 207 208- Draw images and processes image pixel information. 209 210 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). 211 212 ```ts 213 @Entry 214 @Component 215 struct GetImageData { 216 private settings: RenderingContextSettings = new RenderingContextSettings(true) 217 private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings) 218 private offContext: OffscreenCanvasRenderingContext2D = new OffscreenCanvasRenderingContext2D(600, 600, this.settings) 219 private img:ImageBitmap = new ImageBitmap("/common/images/1234.png") 220 221 build() { 222 Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { 223 Canvas(this.context) 224 .width('100%') 225 .height('100%') 226 .backgroundColor('#F5DC62') 227 .onReady(() =>{ 228 // Use the drawImage API to draw an image in the area with the width and height of 130 starting from (0, 0). 229 this.offContext.drawImage(this.img,0,0,130,130); 230 // Use the getImageData API to obtain the drawing content within the range of 130 (width and height) starting from (50, 50) on the canvas. 231 let imagedata = this.offContext.getImageData(50,50,130,130); 232 // Use the putImageData API to draw the obtained image data in the area starting from (150, 150). 233 this.offContext.putImageData(imagedata,150,150); 234 // Draw the offscreen drawing content to the canvas. 235 let image = this.offContext.transferToImageBitmap(); 236 this.context.transferFromImageBitmap(image); 237 }) 238 } 239 .width('100%') 240 .height('100%') 241 } 242 } 243 ``` 244 245 ![drawimage](figures/drawimage.PNG) 246 247- Other usage 248 **Canvas** also provides other usage. Usage related to [canvas gradient](../reference/arkui-ts/ts-components-canvas-canvasgradient.md): [createLinearGradient](../reference/arkui-ts/ts-canvasrenderingcontext2d.md#createlineargradient), [createRadialGradient](../reference/arkui-ts/ts-canvasrenderingcontext2d.md#createradialgradient), and more. 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 color. 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 vertex 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 vertex and clear the area whose width is 150 and height is 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 ib 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 346 347