• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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