Read the original article:Creating a drawable area with canvas
Creating a drawable area with canvas
Requirement Description
Develop a touch-based drawing application with the following features:
- Color Selection: Users can choose between black, red, or blue for drawing.
- Drawing Canvas: A touch-responsive canvas to draw freehand paths.
- Clear Functionality: A button to erase all drawings.
- Path Tracking: Store drawing paths to enable persistent rendering.
Background Knowledge
-
Canvas API: Leverages
CanvasRenderingContext2Dfor drawing operations (e.g.,lineTo,stroke). - Touch Events:
-
TouchType.Down: Start a new path. -
TouchType.Move: Update the current path and render segments.
-
-
State Management:
@Statevariables track paths and color to trigger UI updates.
Implementation Steps
-
Initialize State Variables:
-
paths: 2D array storing all drawn paths. -
currentColor: Tracks the selected drawing color. -
ctx: Canvas rendering context.
-
-
Build UI Components:
-
Color Picker Row: Buttons for colors (
black,red,blue) and a clear button (C). -
Canvas: Configured with
onReady(setup context) andonTouch(handle drawing).
-
Color Picker Row: Buttons for colors (
-
Handle Touch Events:
- Touch Down: Start a new path at the touch coordinates.
- Touch Move: Add points to the latest path and render segments incrementally.
-
Drawing Logic:
-
drawPath(): Connects points in a path with lines and strokes using the current color. - Clear: Reset
pathsand callclearRect()on the canvas.
-
-
Persistent Rendering:
- Paths are preserved in
pathsarray, enabling re-rendering on UI updates (e.g., color change).
- Paths are preserved in
Code Snippet
// DrawingPage.ets
@Entry
@Component
struct DrawingPage {
@State paths: Array<Array<Point>> = []; // Store all paths
@State currentColor: string = 'black';
private settings: RenderingContextSettings = new RenderingContextSettings(true)
private ctx: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings)
build() {
Column() {
// Color Picker
Row() {
Button().onClick(() => this.currentColor = 'black').backgroundColor(Color.Black).borderRadius(0)
Button().onClick(() => this.currentColor = 'red').backgroundColor(Color.Red).borderRadius(0)
Button().onClick(() => this.currentColor = 'blue').backgroundColor(Color.Blue).borderRadius(0)
Button('C').onClick(() => {
this.ctx?.clearRect(0, 0, 1000, 1000);
this.paths = [];
}).borderRadius(0)
}
.padding(15)
// Drawing Canvas
Canvas(this.ctx)
.width('100%')
.height(500)
.backgroundColor('#f0f0f0')
.onReady(() => {
this.ctx = this.ctx as CanvasRenderingContext2D;
this.ctx.lineWidth = 3;
this.ctx.lineCap = 'round';
})
.onTouch((event: TouchEvent) => {
const touch = event.touches[0];
if (!this.ctx) return;
switch (event.type) {
case TouchType.Down:
this.paths.push([{ x: touch.x, y: touch.y }]);
break;
case TouchType.Move:
if (this.paths.length > 0) {
const currentPath = this.paths[this.paths.length - 1];
currentPath.push({ x: touch.x, y: touch.y });
this.drawPath(currentPath);
}
break;
}
})
}
}
// Draw a single path segment
private drawPath(path: Array<Point>) {
if (!this.ctx || path.length < 2) return;
this.ctx.strokeStyle = this.currentColor;
this.ctx.beginPath();
this.ctx.moveTo(path[0].x, path[0].y);
for (let i = 1; i < path.length; i++) {
this.ctx.lineTo(path[i].x, path[i].y);
}
this.ctx.stroke();
}
}
interface Point {
x: number;
y: number;
}

Top comments (0)