Read the original article:How to Draw Text with Different Alignments on Canvas
Requirement Description
When generating text using the CanvasRenderingContext2D method and drawing filled text with fillText, how can the overall text alignment be achieved? For example, center, right, or left alignment?
Background Knowledge
- Canvas provides a canvas component, and the CanvasRenderingContext2D interface allows drawing on the Canvas component using a RenderingContext. The objects that can be drawn include rectangles, text, images, etc.
- The fillText method can draw filled text, but it can only draw text within a specified region each time, making it unable to draw text with different alignments all at once.
Implementation Steps
To draw text with different alignments on Canvas, follow the steps below:
1.Create RenderingContextSettings and CanvasRenderingContext2D objects to configure and manage the Canvas rendering context. Define three variables — leftText, centerText, and rightText — to display left-aligned, center-aligned, and right-aligned text respectively. letterSpacing is used to set the character spacing, and lineX marks the horizontal position of the reference line.
private settings: RenderingContextSettings = new RenderingContextSettings(true)
private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings)
private leftText: string = 'Left-aligned text'
private centerText: string = 'Center-aligned text'
private rightText: string = 'Right-aligned text'
private letterSpacing: number = 10
private lineX: number = 200
2.The getTotalWidth method calculates the total width of the specified text by iterating through each character, accumulating the width of each character and the corresponding spacing to obtain the total width of the text.
getTotalWidth(text: string): number {
let totalWidth = 0
for (let i = 0; i < text.length; i++) {
// Accumulate occupied width
if (i === text.length - 1) {
totalWidth += this.context.measureText(text[i]).width;
} else {
totalWidth += this.context.measureText(text[i]).width + this.letterSpacing;
}
}
return totalWidth
}
3.In the onReady event of the Canvas, first set the pen color to blue and draw a reference line as the alignment baseline. Then, in this event handler, calculate the position for drawing the text and use a loop to call fillText to draw the text with different alignments sequentially:
-
Left Alignment: Determine the starting position for drawing the text by accumulating the width and spacing of each character.
let leftTotalWidth = this.lineX this.context.font = '24vp sans-serif' for (let i = 0; i < this.leftText.length; i++) { this.context.fillText(this.leftText[i], leftTotalWidth, 50); // Accumulate occupied width if (i === this.leftText.length - 1) { leftTotalWidth += this.context.measureText(this.leftText[i]).width; } else { leftTotalWidth += this.context.measureText(this.leftText[i]).width + this.letterSpacing; } } -
Center Alignment: Calculate the total text width first, then set the starting position to
(lineX - totalWidth / 2)to achieve center alignment.
let centerTotalWidth = 0 centerTotalWidth = this.getTotalWidth(this.centerText) centerTotalWidth = this.lineX - centerTotalWidth / 2 for (let i = 0; i < this.centerText.length; i++) { this.context.fillText(this.centerText[i], centerTotalWidth, 90); // Accumulate occupied width if (i === this.centerText.length - 1) { centerTotalWidth += this.context.measureText(this.centerText[i]).width; } else { centerTotalWidth += this.context.measureText(this.centerText[i]).width + this.letterSpacing; } } -
Right Alignment: Calculate the total text width first, then set the starting position to
(lineX - totalWidth)to achieve right alignment.
let rightTotalWidth = 0 rightTotalWidth = this.getTotalWidth(this.rightText) rightTotalWidth = this.lineX - rightTotalWidth for (let i = 0; i < this.rightText.length; i++) { this.context.fillText(this.rightText[i], rightTotalWidth, 130); // Accumulate occupied width if (i === this.rightText.length - 1) { rightTotalWidth += this.context.measureText(this.rightText[i]).width; } else { rightTotalWidth += this.context.measureText(this.rightText[i]).width + this.letterSpacing; } }
Code Snippet
Complete example reference:
@Entry
@Component
struct Index {
private settings: RenderingContextSettings = new RenderingContextSettings(true)
private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings)
private leftText: string = 'Left-aligned text'
private centerText: string = 'Center-aligned text'
private rightText: string = 'Right-aligned text'
private letterSpacing: number = 0
private lineX: number = 116
getTotalWidth(text: string): number {
let totalWidth = 0
for (let i = 0; i < text.length; i++) {
// Accumulate occupied width
if (i === text.length - 1) {
totalWidth += this.context.measureText(text[i]).width;
} else {
totalWidth += this.context.measureText(text[i]).width + this.letterSpacing;
}
}
return totalWidth
}
build() {
Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
Canvas(this.context)
.width('100%')
.height('100%')
.backgroundColor('#ffff00')
.onReady(() => {
this.context.strokeStyle = '#0000ff'
this.context.moveTo(this.lineX, 10)
this.context.lineTo(this.lineX, 160)
this.context.stroke()
// Left Alignment
let leftTotalWidth = this.lineX
this.context.font = '12vp sans-serif'
for (let i = 0; i < this.leftText.length; i++) {
this.context.fillText(this.leftText[i], leftTotalWidth, 50);
// Accumulate occupied width
if (i === this.leftText.length - 1) {
leftTotalWidth += this.context.measureText(this.leftText[i]).width;
} else {
leftTotalWidth += this.context.measureText(this.leftText[i]).width + this.letterSpacing;
}
}
// Center Alignment
let centerTotalWidth = 0
centerTotalWidth = this.getTotalWidth(this.centerText)
centerTotalWidth = this.lineX - centerTotalWidth / 2
for (let i = 0; i < this.centerText.length; i++) {
this.context.fillText(this.centerText[i], centerTotalWidth, 90);
// Accumulate occupied width
if (i === this.centerText.length - 1) {
centerTotalWidth += this.context.measureText(this.centerText[i]).width;
} else {
centerTotalWidth += this.context.measureText(this.centerText[i]).width + this.letterSpacing;
}
}
// Right Alignment
let rightTotalWidth = 0
rightTotalWidth = this.getTotalWidth(this.rightText)
rightTotalWidth = this.lineX - rightTotalWidth
for (let i = 0; i < this.rightText.length; i++) {
this.context.fillText(this.rightText[i], rightTotalWidth, 130);
// Accumulate occupied width
if (i === this.rightText.length - 1) {
rightTotalWidth += this.context.measureText(this.rightText[i]).width;
} else {
rightTotalWidth += this.context.measureText(this.rightText[i]).width + this.letterSpacing;
}
}
})
}
.width('100%')
.height('100%')
}
}
Test Results
Limitations or Considerations
Canvas :
supported since API version 8
Supported devices : Phone PC/2in1 Tablet TV Wearable
CanvasRenderingContext2D :
supported since API version 8,
Supported devices : Phone PC/2in1 Tablet TV Wearable
fillText :
supported since API version 8,
Supported devices : Phone PC/2in1 Tablet TV Wearable

Top comments (0)