Using Drawing to Draw and Display Graphics

When to Use

The @ohos.graphics.drawing module provides basic drawing capabilities, such as drawing rectangles, circles, points, line segments, custom paths, and fonts.

Available APIs

The table below lists the common APIs provided by the @ohos.graphics.drawing module. For details about all the APIs, see @ohos.graphics.drawing.

API Description
drawPath(path: Path) : void Draws a custom path.
drawRect(rect: common2D.Rect): void Draws a rectangle. By default, black is used for filling.
drawTextBlob(blob: TextBlob, x: number, y: number): void Draws a text blob.
moveTo(x: number, y: number) : void Sets the start point of a path.
lineTo(x: number, y: number) : void Draws a line segment from the last point of a path to the target point.
close(): void Draws a line segment from the current point to the start point of a path.
setAntiAlias(aa: boolean) : void Enables anti-aliasing for this pen or brush. Anti-aliasing makes the edges of the content smoother.
setColor(color: common2D.Color) : void Sets a color for this pen or brush.
setStrokeWidth(width: number) : void Sets a stroke width for this pen.
attachPen(pen: Pen): void Attaches a pen to a canvas so that the canvas can use the style and color of the pen to outline a shape.
attachBrush(brush: Brush): void Attaches a brush to a canvas so that the canvas can use the style and color of the brush to fill in a shape.

How to Develop

Use the canvas and pen of the @ohos.graphics.drawing module to draw basic 2D graphics and text blobs, and call the drawing and display logic to display them on the screen.

The following walks you through on how to draw and display 2D graphics and text blobs.

Adding Dependencies

Adding Dynamic Link Libraries

Add the following libraries to CMakeLists.txt.

libace_ndk.z.so
libnative_window.so
libnative_drawing.so

Importing Dependency Files

import { NodeController, FrameNode, RenderNode, DrawContext } from "@ohos.arkui.node"
import { UIContext } from '@ohos.arkui.UIContext'
import drawing from "@ohos.graphics.drawing"
import image from '@ohos.multimedia.image'
import common2D from '@ohos.graphics.common2D'

Now you can use the APIs for drawing.

Drawing 2D Graphics

Follow the steps below to draw 2D graphics and text blobs by using the canvas and pen of the @ohos.graphics.drawing module.

  1. Create a child class of RenderNode. Create the child class MyRenderNode and define drawing functions in it. RenderNode contains operations on the tree structure and drawing attributes.

    // Create the MyRenderNode class.
    class MyRenderNode extends RenderNode {
    
        async draw(context: DrawContext) {
            // ...
        }
    }
    
  2. Construct a path shape.

    Use moveTo, lineTo, and close of the path to construct a pentagram.

    const canvas = context.canvas
    let height_ = 1200
    let width_ = 600
    let len = height_ / 4
    let aX = width_ / 2
    let aY = height_ / 4
    let dX = aX - len * Math.sin(18.0)
    let dY = aY + len * Math.cos(18.0)
    let cX = aX + len * Math.sin(18.0)
    let cY = dY
    let bX = aX + (len / 2.0)
    let bY = aY + Math.sqrt((cX - dX) * (cX - dX) + (len / 2.0) * (len / 2.0))
    let eX = aX - (len / 2.0)
    let eY = bY;
    
    // Create a path object and use the APIs to construct a pentagram.
    let path = new drawing.Path()
    
    // Specify the start point of the path.
    path.moveTo(aX, aY)
    
    // Draw a line segment from the last point of a path to the target point.
    path.lineTo(bX, bY)
    path.lineTo(cX, cY)
    path.lineTo(dX, dY)
    path.lineTo(eX, eY)
    
    // Close the path. Now the path is drawn.
    path.close()
    
  3. Set the pen and brush styles.

    Use Pen to create a pen object, and set the attributes such as anti-aliasing, color, and thickness. The pen is used to outline a shape.

    Use Brush to create a brush object, and set the brush color. The brush is used to fill in a shape.

    Use attachPen and attachBrush in canvas to attach the pen and brush to the canvas.

    // Create a pen object and set the anti-aliasing, color, and thickness attributes.
    let pen = new drawing.Pen()
    pen.setAntiAlias(true)
    let pen_color : common2D.Color = { alpha: 0xFF, red: 0xFF, green: 0x00, blue: 0x00 }
    pen.setColor(pen_color)
    pen.setStrokeWidth(10.0)
      
    // Attach the pen to the canvas.
    canvas.attachPen(pen)
    
    // Create a brush object and set the color.
    let brush = new drawing.Brush()
    let brush_color : common2D.Color = { alpha: 0xFF, red: 0x00, green: 0xFF, blue: 0x00 }
    brush.setColor(brush_color)
    
    // Attach the brush to the canvas.
    canvas.attachBrush(brush)
    
  4. Draw the pentagram.

    Use drawPath in canvas to draw the pentagram on the canvas.

    // Draw the path.
    canvas.drawPath(path)
    
  5. Create a MyRenderNode object.

    Steps 1 to 4 build the MyRenderNode class and define the main drawing functions in it. Next, create a MyRenderNode object and set its pixel format.

    // Create a MyRenderNode object.
    const newNode = new MyRenderNode()
    // Define the pixel format of MyRenderNode.
    newNode.frame = { x: 100, y: 100, width: 200, height: 800 }
    newNode.pivot = { x: 0.2, y: 0.8 }
    newNode.scale = { x: 1, y: 1 }
    
  6. Draw a rectangle.

    Use drawRect in canvas to draw a rectangle.

    class RectRenderNode extends RenderNode {
        async draw(context: DrawContext) {
            const canvas = context.canvas
            const pen = new drawing.Pen()
            pen.setStrokeWidth(5)
            pen.setColor({alpha: 255, red: 255, green: 0, blue: 0})
            canvas.attachPen(pen)
            canvas.drawRect({ left : 200, right : 500, top : 300, bottom : 900})
        }
    }
    // Create a RectRenderNode object.
    const rectNode = new RectRenderNode()
    // Define the pixel format of RectRenderNode.
    rectNode.frame = { x: 90, y: 100, width: 200, height: 800 }
    rectNode.pivot = { x: 0.2, y: 0.8 }
    rectNode.scale = { x: 1, y: 1 }
    
  7. Draw a text blob.

    Use drawTextBlob in canvas to draw a text blob.

    class TextRenderNode extends RenderNode {
        async draw(context: DrawContext) {
            const canvas = context.canvas
            const brush = new drawing.Brush()
            brush.setColor({alpha: 255, red: 255, green: 0, blue: 0})
            const font = new drawing.Font()
            font.setSize(100)
            const textBlob = drawing.TextBlob.makeFromString("Hello World", font, drawing.TextEncoding.TEXT_ENCODING_UTF8)
            canvas.attachBrush(brush)
            canvas.drawTextBlob(textBlob, 90, 500)
        }
    }
    // Create a TextRenderNode object.
    const textNode = new TextRenderNode()
    // Define the pixel format of TextRenderNode.
    textNode.frame = { x: 90, y: 100, width: 200, height: 800 }
    textNode.pivot = { x: 0.2, y: 0.8 }
    textNode.scale = { x: 1, y: 1 }
    
  8. Create a child class of NodeController.

    Create the child class MyNodeController, and define the functions for creating FrameNode in it. NodeController defines the controller of a node container and controls the nodes in the lifecycle of the container. FrameNode defines the basic type of a node and contains a RenderNode.

    class MyNodeController extends NodeController {
        private rootNode: FrameNode | null = null;
    
        makeNode(uiContext: UIContext): FrameNode {
            this.rootNode = new FrameNode(uiContext)
            if (this.rootNode == null) {
                return this.rootNode
            }
            const renderNode = this.rootNode.getRenderNode()
            if (renderNode != null) {
                renderNode.frame = { x: 0, y: 0, width: 10, height: 500 }
                renderNode.pivot = { x: 50, y: 50 }
            }
            return this.rootNode
        }
    }
    
  9. Define an interface for adding a node.

    Define an interface for adding a RenderNode in the MyNodeController class created in step 8.

    addNode(node: RenderNode): void {
        if (this.rootNode == null) {
            return
        }
        const renderNode = this.rootNode.getRenderNode()
        if (renderNode != null) {
            renderNode.appendChild(node)
        }
    }
    
  10. Define an interface for deleting a node.

    Define an interface for deleting a RenderNode in the MyNodeController class created in step 8.

    clearNodes(): void {
        if (this.rootNode == null) {
            return
        }
        const renderNode = this.rootNode.getRenderNode()
        if (renderNode != null) {
            renderNode.clearChildren()
        }
    }
    
  11. Draw the graphics and text blob.

    Create a MyNodeController instance and save it to the NodeContainer, add a <\Button> component, and call the defined interfaces.

    @Entry
    @Component
    struct RenderTest {
        private myNodeController: MyNodeController = new MyNodeController()
        build() {
            Column() {
                Row() {
                    NodeContainer(this.myNodeController)
                        .height('100%')
                    Button("Draw Path")
                        .margin({ bottom: 200, right: 12 })
                        .onClick(() => {
                            this.myNodeController.clearNodes()
                            this.myNodeController.addNode(newNode)
                        })
                    Button("Draw Rect")
                        .margin({ bottom: 200, right: 12 })
                        .onClick(() => {
                            this.myNodeController.clearNodes()
                            this.myNodeController.addNode(rectNode)
                        })
                    Button("Draw Text")
                        .margin({ bottom: 200, right: 12 })
                        .onClick(() => {
                            this.myNodeController.clearNodes()
                            this.myNodeController.addNode(textNode)
                        })
                }
                .width('100%')
                .justifyContent(FlexAlign.Center)
                .shadow(ShadowStyle.OUTER_DEFAULT_SM)
                .alignItems(VerticalAlign.Bottom)
                .layoutWeight(1)
            }
        }
    }
    

    The following figure shows the drawing and display effect.

Home page Pentagram drawn Rectangle drawn Text blob drawn
main Draw Path Draw Path Draw Path