# PaletteDemo **Repository Path**: dot_happydz_admin/PaletteDemo ## Basic Information - **Project Name**: PaletteDemo - **Description**: 基于HarmonyOS API=9 Stage模型 开发的画板 - **Primary Language**: Unknown - **License**: Apache-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 1 - **Created**: 2024-02-25 - **Last Updated**: 2025-02-20 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # ArkTS Canvas项目实战:画板 ### **项目介绍** **项目内容:** 1、画笔功能:可设置画笔粗细和颜色;2、橡皮擦功能:可设置粗细;3、撤回和回撤功能;4:清空画板功能; **工具版本:** DevEco Studio 3.1 Canary1 **SDK版本:** 3.2.1.4(API Version 9 Canary1)(Stage模型) 本项目基于[HarmonyOS](https://developer.harmonyos.com/cn/docs/documentation/doc-guides-V3/start-overview-0000001380121578-V3)的ArkUI框架TS扩展的声明式开发范式,关于语法和概念直接看官网官方文档地址:[基于TS扩展的声明式开发范式](https://developer.harmonyos.com/cn/docs/documentation/doc-guides-V3/arkts-get-started-0000001430600477-V3) ### 效果演示 ![](image/demo.gif) ### 用到的API [画布组件canvas](https://developer.harmonyos.com/cn/docs/documentation/doc-references/ts-components-canvas-canvas-0000001333641081):画布组件,用于自定义绘制图形。 | 方法/属性 | 解释 | | :----------------------- | :--------------------------- | | beginPath() | 创建一个新的绘制路径 | | moveTo() | 路径从当前点移动到指定点 | | lineTo() | 从当前点到指定点进行路径连接 | | stroke() | 进行边框绘制操作 | | clearRect() | 清空画布 | | strokeStyle | 属性:设置描边的颜色 | | lineWidth | 属性:设置绘制线条的宽度 | | globalCompositeOperation | 属性:设置合成操作的方式 | ### 实现思路 #### 画笔功能 使用onTouch方法,监听触摸事件,手指按下:使用方法moveTo记录起点,手指移动:使用方法beginPath创建新的路径,lineTo记录移动的点,并绘制。 ![](image/demo1.gif) **(代码片段,详细请查看源码)** ```js /** * 触摸事件 */ onTouchEvent(event: TouchEvent) { // x坐标 const x = event.touches[0].x // y坐标 const y = event.touches[0].y switch (event.type) { case TouchType.Down: // 手指按下 { // 创建一个新的绘制路径 this.crc.beginPath() // 设置起点坐标 this.crc.moveTo(x, y) } break; case TouchType.Move: // 手指移动 case TouchType.Up: // 手指抬起 { // 设置移动点 this.crc.lineTo(x, y) // 进行路径绘制 this.crc.stroke() } break; default: break; } } ``` #### 画笔样式 1、画笔的宽度使用canvas的属性:lineWidth来控制,使用[滑动条组件Slider](https://developer.harmonyos.com/cn/docs/documentation/doc-references/ts-basic-components-slider-0000001281201142) 来更改线的宽度。 2、画笔的颜色使用canvas的属性:strokeStyle来控制,使用自定义颜色选择器。看我之前的帖子:[ ArkUI(TS)声明式开发:颜色选择器 ](https://developer.huawei.com/consumer/cn/forum/topic/0203935191466540881?fid=0102683795438680754) ```javascript // 线的宽度 this.crc.lineWidth = 5 // 线的颜色 this.crc.strokeStyle = 'rgba(0,0,0,0)' ``` #### 橡皮擦功能 设置绘制属性:globalCompositeOperation 画笔设置此属性值: source-over (默认值 在现有绘制内容上显示新绘制内容),橡皮擦设置此属性值: destination-out ( 在新绘制内容外显示现有绘制内容) ```javascript // 新内容在之前内容的之上 this.crc.globalCompositeOperation = 'source-over' // 新内容与之前内容相交位置变透明 this.crc.globalCompositeOperation = 'destination-out' ``` #### 撤回和回撤功能 数据类,记录每次绘制的信息,线颜色、宽度、坐标点集合,每次画完保存到数组中 ```javascript /** * 绘制信息 * @param lineColor 线颜色 * @param lineWidth 线宽度 * @param listCoord 坐标点集合 */ export class DrawInfoModel { // 是否为画笔,是:画笔,否:橡皮擦 // 根据此字段设置绘制属性:合成操作globalCompositeOperation isPen: boolean; // 线颜色 lineColor: string; // 线宽度 lineWidth: number; // 坐标点集合 listCoord: Array; constructor(isPen: boolean, lineColor: string, lineWidth: number, listCoord: Array) { this.isPen = isPen; this.lineColor = lineColor; this.lineWidth = lineWidth; this.listCoord = listCoord; } } /** * 坐标点 * @param x 坐标点x * @param y 坐标点y */ export class Coord { // 坐标点x x: number; // 坐标点y y: number; constructor(x: number, y: number) { this.x = x; this.y = y; } } ``` 每次绘制的信息,保存在数组中,在点击撤回时,撤回数+1;回撤时,撤回数-1,并截取数组,清空画布,遍历数组绘制笔画信息。 **(代码片段,详细请查看源码)** ```javascript /** * 撤回 */ revocation() { this.listTempXY = this.listAllXY ...... // 根据撤回的个数,截取数组 this.listTempXY = this.listTempXY.slice(0, this.listTempXY.length - this.revocationNumber) // 清空画布 this.crc.clearRect(0, 0, this.canvasWidth, this.canvasHeight) // 拼接笔画路径 for (const drawInfo of this.listTempXY) { // 创建一个新的绘制路径 this.crc.beginPath() // 设置线颜色 this.crc.strokeStyle = drawInfo.lineColor // 设置线宽度 this.crc.lineWidth = drawInfo.lineWidth // 设置绘制的坐标点 for (let i = 0;i < drawInfo.listCoord.length; i++) { const coord = drawInfo.listCoord[i] // 第一个设置为起点 if (i === 0) { this.crc.moveTo(coord.x, coord.y) } else { this.crc.lineTo(coord.x, coord.y) } } // 进行路径绘制 this.crc.stroke() } } ``` #### 清空 点击清空弹框,需要自定义弹框样式,确认点击事件提供给外部实现。 ```javascript @CustomDialog export struct HintDialog { private controller: CustomDialogController private title = '标题' private content = '内容' private btnCancelText = '取消' private btnConfirmText = '确定' private cancel: () => void private confirm: () => void build() { Column() { Text(this.title) .textAlign(TextAlign.Center) .width('100%') .fontSize(20) .padding(15) Text(this.content) .fontSize(17) .padding(15) Flex({ justifyContent: FlexAlign.SpaceAround }) { Button(this.btnCancelText) .onClick(() => { this.controller.close() this.cancel() }).backgroundColor(Color.White) .fontColor('#3879F8') .fontSize(16) Button(this.btnConfirmText) .onClick(() => { this.controller.close() this.confirm() }).backgroundColor(Color.White) .fontColor('#3879F8') .fontSize(16) }.margin({ top: 10, bottom: 15 }) } } } ``` 在Index页面中,实现自定义弹框的确认事件,更改其他操作的状态,并清空数组、最后清空整体画布。 ```javascript // 自定义提示框 private dialogController: CustomDialogController = new CustomDialogController({ builder: HintDialog({ title: '清空画板', content: '确定清空当前画板?', confirm: () => { // 撤回不可用 this.revocationEnabled = false // 回撤不可用 this.unRevocationEnabled = false // 清空不可用 this.clearEnabled = false // 记录的数组清空 this.listTempXY = [] this.listAllXY = [] // 选中画笔 this.isSelectPen = true // 清空画布 this.crc.clearRect(0, 0, this.canvasWidth, this.canvasHeight) } }), }) ``` ### 结尾 此项目并没有特别复杂的地方,注释也很详细,以上列出的代码都是实现主要的功能,颜色选择功能查看我之前的帖子,其他细节请查看源码,最后不得不感慨声明式语法的强大和简洁性,完成此功能相对于使用JS来实现效率提升很高,也希望鸿蒙社区越来越好,融入更多的热爱者。 项目地址:[https://gitee.com/liangdidi/PaletteDemo](https://gitee.com/liangdidi/PaletteDemo) 每天进步一点点、需要付出努力亿点点。