1# Obtaining a Canvas and Displaying Drawing Results (ArkTS) 2 3 4## When to Use 5 6Canvas provides the capability of drawing basic graphics on the screen. You can use Canvas to customize drawing effects to enhance user experience. 7 8 9Canvas is the core of graphics drawing. All drawing operations (including basic graphics drawing, text drawing, image drawing, and image transformation) mentioned in this chapter are based on Canvas. 10 11 12Currently, ArkTS can obtain the canvas in either of the following ways: [Obtaining the Canvas That Can Be Directly Displayed](#obtaining-the-canvas-that-can-be-directly-displayed) and [Obtaining and Displaying the Off-Screen Canvas](#obtaining-and-displaying-the off-screen-canvas). The former can display the drawing result on the screen without additional operations after the drawing API is called, while the latter can display the drawing result using existing display methods. 13 14 15## Obtaining the Canvas That Can Be Directly Displayed 16 17Use [RenderNode](../reference/apis-arkui/js-apis-arkui-renderNode.md) to obtain the canvas that can be directly displayed on the screen. 18 191. Add a customized RenderNode. 20 212. Add a customized [NodeController](../reference/apis-arkui/js-apis-arkui-nodeController.md). 22 233. Rewrite the [draw()](../reference//apis-arkui/js-apis-arkui-renderNode.md#draw) function of the customized RenderNode to obtain the Canvas for customized drawing. 24 254. Displays the customized NodeController. 26 27```ts 28import { UIContext, NodeController, FrameNode, RenderNode, DrawContext } from '@kit.ArkUI'; 29import { drawing } from '@kit.ArkGraphics2D'; 30 31// 1. Customize a RenderNode. 32export class MyRenderNode extends RenderNode { 33 async draw(context: DrawContext) { 34 const canvas = context.canvas 35 // 3. Custom drawing operations 36 const brush = new drawing.Brush() 37 brush.setColor({red: 255, blue: 0, green: 0, alpha: 255}) 38 canvas.attachBrush(brush) 39 canvas.drawRect({left: 0, right: 300, top: 0, bottom: 300}) 40 } 41} 42 43// 2. Customize a NodeController. 44export class MyNodeController extends NodeController { 45 private rootNode: FrameNode | null = null; 46 myRenderNode = new MyRenderNode(); 47 48 makeNode(uiContext: UIContext): FrameNode { 49 this.rootNode = new FrameNode(uiContext); 50 if (this.rootNode === null) { 51 return this.rootNode 52 } 53 54 const renderNode = this.rootNode.getRenderNode(); 55 if (renderNode !== null) { 56 this.myRenderNode.backgroundColor = 0xffffffff; 57 this.myRenderNode.frame = { x: 0, y: 0, width: 4800, height: 4800 }; 58 this.myRenderNode.pivot = { x: 0.2, y: 0.8 } 59 this.myRenderNode.scale = { x: 1, y: 1 } 60 renderNode.appendChild(this.myRenderNode); 61 renderNode.clipToFrame = true 62 } 63 return this.rootNode; 64 } 65} 66 67@Entry 68@Component 69struct RenderTest { 70 @State message: string = 'hello' 71 build() { 72 Row() { 73 Column() { 74 // 4. Display the custom NodeController. 75 NodeContainer(new MyNodeController()) 76 .width('100%') 77 } 78 .width('100%') 79 .height('80%') 80 } 81 .height('100%') 82 } 83} 84``` 85 86 87## Obtaining and Displaying the Off-Screen Canvas 88 891. Add a customized RenderNode. 90 912. Add a customized [NodeController](../reference/apis-arkui/js-apis-arkui-nodeController.md). 92 933. Create a PixeMap in the aboutToAppear() function of MyNodeController. 94 954. Rewrite the [draw()](../reference//apis-arkui/js-apis-arkui-renderNode.md#draw) function of the custom RenderNode to obtain the off-screen Canvas for drawing. 96 97 1. Use the pixel map created in step 3 to construct an off-screen canvas. 98 2. Performs customized drawing operations on the off-screen Canvas. 99 3. Sends the drawing result of the off-screen Canvas to the RenderNode. 100 1015. Displays the customized NodeController. 102 103```ts 104import { UIContext, NodeController, FrameNode, RenderNode, DrawContext } from '@kit.ArkUI'; 105import { image } from '@kit.ImageKit'; 106import { taskpool } from '@kit.ArkTS'; 107import { drawing } from '@kit.ArkGraphics2D'; 108 109// 1. Customize a RenderNode. 110export class MyRenderNode extends RenderNode { 111 pixelMap: image.PixelMap | null = null; 112 setPixelMap(pixelMap: image.PixelMap) { 113 this.pixelMap = pixelMap 114 } 115 116 async draw(context: DrawContext) { 117 const canvas = context.canvas 118 if (this.pixelMap != null) { 119 // 4.1 Use the pixel map created in step 3 to construct an off-screen canvas. 120 const canvas_ = new drawing.Canvas(this.pixelMap); 121 122 // 4.2 Off-screen drawing 123 const brush = new drawing.Brush(); 124 brush.setColor({ alpha: 255, red: 255, green: 0, blue: 0 }); 125 canvas_.attachBrush(brush); 126 canvas_.drawRect({left:0,right:100,top:0,bottom:100}); 127 128 // 4.3 Send the drawing result of the off-screen Canvas to RenderNode. 129 canvas.drawImage(this.pixelMap, 0, 0); 130 } 131 } 132} 133 134@Concurrent 135async function CreatePixelMapAsync() { 136 const color : ArrayBuffer = new ArrayBuffer(40000); // 40000 is the size of the pixel buffer to create. The value is calculated as follows: height * width *4. 137 let opts : image.InitializationOptions = { editable: true, pixelFormat: 3, size: { height: 100, width: 100 } } 138 const pixel = await image.createPixelMap(color, opts); 139 return pixel; 140} 141 142// 2. Customize a NodeController. 143export class MyNodeController extends NodeController { 144 private rootNode: FrameNode | null = null; 145 myRenderNode = new MyRenderNode(); 146 147 // 3. Create a PixeMap in aboutToAppear of MyNodeController. 148 aboutToAppear(): void { 149 let task = new taskpool.Task(CreatePixelMapAsync); 150 taskpool.execute(task).then((pixel:Object)=>{ 151 this.myRenderNode.setPixelMap(pixel as image.PixelMap) 152 this.myRenderNode.invalidate() 153 }) 154 } 155 156 makeNode(uiContext: UIContext): FrameNode { 157 this.rootNode = new FrameNode(uiContext); 158 if (this.rootNode === null) { 159 return this.rootNode 160 } 161 162 const renderNode = this.rootNode.getRenderNode(); 163 if (renderNode !== null) { 164 this.myRenderNode.backgroundColor = 0xffffffff; 165 this.myRenderNode.frame = { x: 0, y: 0, width: 4800, height: 4800 }; 166 this.myRenderNode.pivot = { x: 0.2, y: 0.8 } 167 this.myRenderNode.scale = { x: 1, y: 1 } 168 renderNode.appendChild(this.myRenderNode); 169 renderNode.clipToFrame = true 170 } 171 return this.rootNode; 172 } 173} 174 175 176@Entry 177@Component 178struct RenderTest { 179 @State message: string = 'hello' 180 nodeController = new MyNodeController() 181 182 build() { 183 Row() { 184 Column() { 185 // 5. Display the custom NodeController. 186 NodeContainer(this.nodeController) 187 .width('100%') 188 } 189 .width('100%') 190 .height('80%') 191 } 192 .height('100%') 193 } 194} 195``` 196