[HarmonyOS 5] HarmonyOS implements a handwriting tablet
Create an interactive component where when the user touches and moves their finger on the screen, a path is dynamically generated based on the position of the touch and drawn on the screen.
[HarmonyOS 5] HarmonyOS implements a handwriting tablet
I. Introduction
The basic idea of implementing a tablet function is as follows:
Create an interactive component where when the user touches and moves their finger on the screen, a path is dynamically generated based on the position of the touch and drawn on the screen with a black stroke. When the user presses the screen, the coordinates of the press point are recorded as the starting point of the path. When the user moves his finger, the coordinates of the moving points are constantly recorded, and the path is formed by connecting the line segments.
The functional renderings are as follows:
Second, the idea of the program
The system provides a very convenient line drawing component Path. This component combines canvas and line drawing functions into one. A concise line drawing component is provided.
For more information, see Path-Graph-Draw-ArkTS Components-ArkUI (Ark UI Framework)-Application Frameworks - Huawei HarmonyOS Developer https://developer.huawei.com/consumer/en/doc/harmonyos-guides-V14/drawing-guidelines-V14
The idea of using the Path component is very simple, as shown in the following code:
javascript
Code interpretation
Copy the code
Path() .commands(this.pathCommands) // 设置SVG路径描述字符串 .strokeWidth(5) // 设置路径的描边宽度为 5 .fill("none") // 设置路径的填充颜色为无 .stroke(Color.Black) // 设置路径的描边颜色为黑色 .height('100%') .width('100%')
1. Set the width and height of the component to the size of the canvas area to be displayed.
height and width are 100 percent.
2. Set the style, color, and width of the line.
stroke is Color.Black and strokeWidth is 5
3. Set the color of the filled area where the closed is drawn.
fill is none
If you change the fill color, you will get the following effect:
Since this effect is not required for the tablet, you need to set fill to none, not fill color.
4. Set the SVG path description string.
The most core property of the component. Its value is a string and looks something like this:
javascript
Code interpretation
Copy the code
M225.99999999999997 409.99999999999994 L225.99999999999997 409.99999999999994
First, let's understand what the SVG path descriptor does.
SVG path descriptors are a set of commands used to define vector graphics paths, and play a key role in drawing graphics using the Path component, creating a variety of complex custom shapes. The main functions are as follows:
(1) Build a basic graph:
The M (moveto) command is used to determine the starting point, and the L (lineto), H (horizontal lineto), V (vertical lineto) and other commands are used to draw straight line segments, and basic shapes such as triangles and rectangles can be constructed. For example, commands('M0 20 L50 50 L50 100 Z') defines a triangle that starts at (0,20), draws two straight segments, and ends with the Z(closepath) command to close the path.
(2) Draw a curve graph:
With the help of C (curveto), S (smooth curveto), Q (quadratic Belzier curve), T (smooth quadratic Belzier curveto) and other commands, different types of Bezier curves can be drawn to achieve complex curve drawing. Like C100 100 250 100 250 200 you can draw a cubic Bezier curve from the current point to the (250, 200) point, which can be used to create curve shapes such as petals, wavy lines, etc.
(3) Draw elliptical arcs:
The A (elliptical arc) command is used to draw elliptical arcs from the current point to a specified point, and by setting the radius, rotation angle, and other flags of the ellipse, you can draw partial arcs of various elliptical shapes, such as the sectors of a pie chart.
In the handwriting tablet scenario, the SVG path descriptor uses only the M (moveto) and L (lineto) commands to achieve its primary function. The reason for this is that the core requirement of the tablet is to record and present the trajectory drawn by the user in real time. The M command is used to determine the starting point of the drawing track, and every time the user touches the screen to start writing, it is equivalent to starting a new path, and the M command records this starting coordinate, as if determining the landing point of the first stroke on paper. The L command draws a line from the current point to the specified coordinates, and in the tablet, with the movement of the user's fingers, the coordinate points in the process of movement are continuously obtained, and the points are connected in turn through the L command to form a continuous line and accurately present the handwritten handwriting.
In the end, we only need to add the onTouch event outside the Path component to record the user's finger touch event, get its x,y coordinates, and then implement the svg path descriptor of the tablet:
javascript
Code interpretation
Copy the code
// 处理触摸事件的方法 onTouchEvent(event: TouchEvent) { // 根据触摸事件的类型进行不同的处理 switch (event.type) { // 当触摸类型为按下时 case TouchType.Down: // 在 pathCommands 中添加一个移动命令(M),并记录按下点的坐标 this.pathCommands += 'M' + event.touches[0].x + ' ' + event.touches[0].y; break; // 当触摸类型为移动时 case TouchType.Move: // 在 pathCommands 中添加一个线段命令(L),并记录移动点的坐标 this.pathCommands += 'L' + event.touches[0].x + ' ' + event.touches[0].y; break; // 其他触摸类型,不做处理 default: break; } }
5. When it is time to empty the tablet.
All you need to do is set the commands property of the Path component to an empty string.
3. Source code example:
javascript
Code interpretation
Copy the code
@Entry @Component struct PathTestPage { @State pathCommands: string = ""; private setPathCommands(str: string, event: TouchEvent){ let x = event.touches[0].x; let y = event.touches[0].y; this.pathCommands += str + vp2px(x) + ' ' + vp2px(y); console.log("georgeDebug", " this.pathCommands: " + this.pathCommands); } onTouchEvent(event: TouchEvent){ // event xy 单位:vp switch (event.type){ case TouchType.Down: this.setPathCommands('M', event); break; case TouchType.Move: this.setPathCommands('L', event); break; default: break; } } build() { Stack({ alignContent: Alignment.TopStart }){ Path() .commands(this.pathCommands) // 设置SVG路径描述字符串 .strokeWidth(5) // 设置路径的描边宽度为 5 .fill("none") // 设置路径的填充颜色为无 .stroke(Color.Black) // 设置路径的描边颜色为黑色 .height('100%') .width('100%') .onTouch((event: TouchEvent)=>{ this.onTouchEvent(event); }) Button("清空绘制") .onClick(()=>{ this.pathCommands = ""; }) } .height('100%') .width('100%') } }
Note:
Since path cannot be used as the root node of the build, it is wrapped with container component row.
The xy unit of coordinates obtained by onTouch is vp, and the unit of svg descriptor is vp, so the value should be converted to units. Otherwise, you'll be able to draw something, but the coordinates and the position of the pen will be reduced.
You need to set the width and height of the path component, otherwise it will not be displayed.
作者:GeorgeGcs
链接:https://juejin.cn/post/7491984282539524135
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。