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/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 .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 created **ImageBitmap** object. 47 48 For details, see [OffscreenCanvasRenderingContext2D](../reference/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 .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.jpg) 113 114 115## Canvas Component Drawing Modes 116 117Two modes are available for drawing with the **Canvas** component: 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 .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/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 .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/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, attributes such as [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) 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/arkui-ts/ts-canvasrenderingcontext2d.md#arc), [ellipse](../reference/arkui-ts/ts-canvasrenderingcontext2d.md#ellipse), and [rect](../reference/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 .jpg) 182 183- Draw text. 184 185 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. 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 sans-serif'; 195 this.context.fillText("Hello World!", 50, 100); 196 // Draw a text stroke on the canvas. 197 this.context.font = '55px sans-serif'; 198 this.context.strokeText("Hello World!", 50, 150); 199 }) 200 ``` 201 202 .jpg) 203 204- Draw images and processes image pixel information. 205 206 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). 207 208 ```ts 209 @Entry 210 @Component 211 struct GetImageData { 212 private settings: RenderingContextSettings = new RenderingContextSettings(true) 213 private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings) 214 private offCanvas: OffscreenCanvas = new OffscreenCanvas(600, 600) 215 private img:ImageBitmap = new ImageBitmap("/common/images/1234.png") 216 217 build() { 218 Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { 219 Canvas(this.context) 220 .width('100%') 221 .height('100%') 222 .backgroundColor('#F5DC62') 223 .onReady(() =>{ 224 let offContext = this.offCanvas.getContext("2d", this.settings) 225 // Use the drawImage API to draw an image in the area with the width and height of 130 starting from (0, 0). 226 offContext.drawImage(this.img,0,0,130,130); 227 // Use the getImageData API to obtain the image data with the width and height of 130 starting from (50, 50). 228 let imagedata = offContext.getImageData(50,50,130,130); 229 // Use the putImageData API to draw the obtained image data in the area starting from (150, 150). 230 offContext.putImageData(imagedata,150,150); 231 // Draw the offscreen drawing content to the canvas. 232 let image = this.offCanvas.transferToImageBitmap(); 233 this.context.transferFromImageBitmap(image); 234 }) 235 } 236 .width('100%') 237 .height('100%') 238 } 239 } 240 ``` 241 242  243 244- Other usage 245 246 **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. 247 248 ```ts 249 Canvas(this.context) 250 .width('100%') 251 .height('100%') 252 .backgroundColor('#F5DC62') 253 .onReady(() =>{ 254 // Create a CanvasGradient object with radial gradient colors. 255 let grad = this.context.createRadialGradient(200,200,50, 200,200,200) 256 // Set the gradient color stop for the CanvasGradient object, including the offset and colors. 257 grad.addColorStop(0.0, '#E87361'); 258 grad.addColorStop(0.5, '#FFFFF0'); 259 grad.addColorStop(1.0, '#BDDB69'); 260 // Fill the rectangle with the CanvasGradient object. 261 this.context.fillStyle = grad; 262 this.context.fillRect(0, 0, 400, 400); 263 }) 264 ``` 265 266 .jpg) 267 268 269## Example Scenario 270 271- Draw a basic shape. 272 273 ```ts 274 @Entry 275 @Component 276 struct ClearRect { 277 private settings: RenderingContextSettings = new RenderingContextSettings(true); 278 private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings); 279 280 build() { 281 Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { 282 Canvas(this.context) 283 .width('100%') 284 .height('100%') 285 .backgroundColor('#F5DC62') 286 .onReady(() =>{ 287 // Set the fill color to blue. 288 this.context.fillStyle = '#0097D4'; 289 // Take (50, 50) as the upper left corner and draw a rectangle with the width and height of 200. 290 this.context.fillRect(50,50,200,200); 291 // Use (70, 70) as the upper left corner and clear the area with the width of 150 and height of 100. 292 this.context.clearRect(70,70,150,100); 293 }) 294 } 295 .width('100%') 296 .height('100%') 297 } 298 } 299 300 ``` 301 302 .jpg) 303 304- Draw an irregular shape. 305 306 ```ts 307 @Entry 308 @Component 309 struct Path2d { 310 private settings: RenderingContextSettings = new RenderingContextSettings(true); 311 private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings); 312 313 build() { 314 Row() { 315 Column() { 316 Canvas(this.context) 317 .width('100%') 318 .height('100%') 319 .backgroundColor('#F5DC62') 320 .onReady(() =>{ 321 // Use the Path2D API to create a pentagon. 322 let path = new Path2D(); 323 path.moveTo(150, 50); 324 path.lineTo(50, 150); 325 path.lineTo(100, 250); 326 path.lineTo(200, 250); 327 path.lineTo(250, 150); 328 path.closePath(); 329 // Set the fill color to blue. 330 this.context.fillStyle = '#0097D4'; 331 // Draw the pentagon described by Path2D in the canvas in fill mode. 332 this.context.fill(path); 333 }) 334 } 335 .width('100%') 336 } 337 .height('100%') 338 } 339 } 340 ``` 341 342  343