# canvas-draw-utils **Repository Path**: Fie_Ryan/canvas-draw-utils ## Basic Information - **Project Name**: canvas-draw-utils - **Description**: CanvasDrawUtils 是一个基于 AtkTs 开发的 Canvas 绘制工具类,采用单例模式设计,封装了路径绘制、文本绘制、图形绘制、样式管理、绘制记录(撤销 / 重做)等核心功能。该工具提供统一的 Canvas 绘制入口,确保全局绘制状态一致性,适用于移动端触摸绘图场景(如签名、标注、简单图形绘制等)。 - **Primary Language**: Unknown - **License**: Apache-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2025-09-26 - **Last Updated**: 2025-10-24 ## Categories & Tags **Categories**: Uncategorized **Tags**: 鸿蒙, ArkTS, Cancvs, 画板自定义绘制, Cancvs绘制 ## README # CanvasDrawUtils - Canvas 绘制工具类 ## 概述 CanvasDrawUtils 是一个基于 ArkTs 开发的 Canvas 绘制工具类,采用单例模式设计,封装了路径绘制、文本绘制、图形绘制、样式管理、绘制记录(撤销 / 重做)等核心功能。该工具提供统一的 Canvas 绘制入口,确保全局绘制状态一致性,适用于移动端触摸绘图场景(如签名、标注、简单图形绘制等)。 ## 安装及初始化使用 ### 1. 安装 ``` ohpm i @ryan/canvas_utils ``` ### 2. 初始化使用 **必须在使用任何绘制功能前调用 `init()` 方法**,传入有效的 CanvasRenderingContext2D 上下文: ``` // 引入工具类 import CanvasDrawUtils from "@ryan/canvas_utils"; // 调用 init() 方法,传入有效的 Canvas 2D 上下文进行初始化 private setting: RenderingContextSettings = new RenderingContextSettings(true); private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.setting); aboutToAppear(): void { CanvasDrawUtils.init(this.context) } ``` ## 核心特性 1. **单例模式**:全局唯一实例,确保绘制状态(样式、记录)一致性。 2. **多类型绘制**:支持路径绘制(触摸事件驱动)、文本绘制、基础图形绘制(矩形等)。 3. **样式管理**:提供全局样式设置 / 获取,支持部分样式合并更新,自动同步到所有绘制模块。 4. **绘制记录**:支持绘制内容的记录、清空、按 ID 删除,以及撤销 / 重做功能。 5. **类型安全**:基于 TypeScript 接口定义,确保参数、返回值类型合规。 6. **初始化校验**:所有功能调用前自动校验初始化状态,避免无效操作。 ## 文件结构 ``` ├──src/main/ets │ ├──common/ │ │ └── Logger.ets # 日志工具类,封装系统日志接口并提供环境区分能力 │ ├──constants/ │ │ └── LoggerConstants.ets # 日志常量 │ ├──enum/ │ │ └── DiagramType.ets # 图形元素类型 │ ├──example/ │ │ ├── common/CommonConstants.ets # page 常量 │ │ ├── components/color.ets # 颜色转换工具函数 │ │ ├── components/ControllerRecord.ets # 绘制操作记录组件 │ │ ├── components/MyPaintSheet.ets # 绘制样式选择组件 │ │ ├── components/Navbar.ets # navbar租金 │ │ ├── pages/DiagramPage.ets # 图形绘制组件 │ │ ├── pages/PathPage.ets # 路径绘制组件 │ │ └── pages/TextPage.ets # 文本绘制组件 │ ├──model/ │ │ └── DefaultModel.ets # 默认数据配置 │ ├──type │ │ ├── CanvasStyle.ets # canvas样式类型 │ │ ├── Drawable.ets # 绘制对象接口类型 │ │ ├── DrawOptions.ets # 绘制的选项类型 │ │ └── Lifecycle.ets # 监听的生命周期类型 │ ├──utils │ │ ├── BaseCanvasDrawUtils.ets # canvas 绘制的基类 │ │ ├── CanvasDrawUtils.ets # canvas 绘制工具类 │ │ ├── MapUtils.ets # Map 工具类 │ │ ├── ObjectUtils.ts # Object 工具类 │ │ └── RandomUtils.ets # 随机函数工具类 │ ├──viewmodel │ │ ├── BaseDrawable.ets # 可绘制元素基类 │ │ ├── BaseDrawViewModel.ets # 绘制模型基类 │ │ ├── DrawDiagram.ets # 图形绘制模型类 │ │ ├── DrawPath.ets # 路径绘制模型类 │ │ ├── DrawRecord.ets # 操作记录器 │ │ └── DrawText.ets # 文本绘制模型类 └──src/main/resource # 资源目录 ``` ## 绘制功能核心API ```extendtypescript /** * Canvas绘制工具类(单例) * 继承自基础Canvas绘制工具类,封装路径绘制、样式管理、绘制记录等核心功能 * 提供统一的Canvas绘制入口,确保全局绘制状态一致性 */ export class CanvasDrawUtils { /** * 处理路径绘制触摸事件 * 驱动路径绘制视图模型执行触摸事件处理逻辑 * @param event 触摸事件对象 * @param drawType 绘制类型(可选,默认描边) * @throws {Error} 当工具未初始化时抛出错误 */ public drawPath(event: TouchEvent, drawType: DrawType = "stroke"): void; /** * 处理文本绘制 * @param text 文本内容 * @param textOptions 文本的配置信息 */ public drawText(text: string, textOptions: DrawTextOptions); /** * 处理图形绘制 * @param type 图形绘制类型, 默认是矩形(rect) * @param location 绘制的位置信息 */ public drawDiagram(type: DiagramTypeEnum | DiagramType = DiagramTypeEnum.RECT, location: Location); /** * 获取所有绘制记录的配置信息 * 将绘制记录映射表转换为普通对象,便于序列化或外部使用 * @returns Record 绘制记录配置(键为记录ID,值为配置) */ public getDrawRecords(): Record; /** * 设置全局自定义绘制样式 * 合并现有样式与新样式,并同步到路径绘制视图模型 * @param style 要应用的自定义样式(支持部分样式更新) * @throws {Error} 当工具未初始化时抛出错误 */ public setGlobalStyle(style: Partial): void; /** * 获取当前全局绘制样式 * 返回样式副本,避免外部直接修改内部状态 * @returns CanvasStyle 当前全局样式的副本 */ public getCurrentGlobalStyle(): CanvasStyle; /** * 销毁单例实例(用于测试或特殊场景) * 重置实例状态,允许重新初始化 */ public destroyInstance(): void; /** * 清除所有绘制内容 * 清空绘制记录并清除Canvas画布 * @throws {Error} 当工具未初始化时抛出错误 */ public clearAllDrawContent(): void; /** * 清除指定ID的绘制内容 * @throws {Error} 当工具未初始化时抛出错误 */ public clearDrawContentById(id: string): void; /** * 撤销 */ public undoDrawContent(): void; /** * 重新绘制 */ public redoDrawContent(): void; /** * 是否可以撤销绘制 * @returns true: 是, false: 否 */ public canUndoDraw(): boolean; /** * 是否可以重新绘制 * @returns true: 是, false: 否 */ public canRedoDraw(): boolean; } ``` ## 监听生命周期 ```extendtypescript /** * 定义画布元素的生命周期钩子接口 * 用于管理与CanvasRenderingContext2D相关的初始化和清理操作 */ export interface Lifecycle { /** * CanvasRenderingContext2D 与 Canvas 组件发生绑定时调用 * 可用于执行初始化操作,如设置样式、绘制初始状态等 * @param context - 画布渲染上下文 */ onAttach?: (context: CanvasRenderingContext2D) => void; /** * CanvasRenderingContext2D 与 Canvas 组件解除绑定时调用 * 可用于执行清理操作,如移除事件监听器、释放资源等 * @param context - 画布渲染上下文 */ onDetach?: (context: CanvasRenderingContext2D) => void; /** * CanvasDrawUtils 发生错误或异常时触发 * @param message - 错误信息 */ onError?: (message: string) => void } ``` ## 使用示例(以路径绘制为例) ```extendtypescript /** * 路径演示示例 */ @Component export struct PathPage { private setting: RenderingContextSettings = new RenderingContextSettings(true); private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.setting); // 省略代码... ToggleThicknessColor() { // 设置 canvas 样式 CanvasDrawUtils.setGlobalStyle({ lineWidth: this.strokeWidth, strokeStyle: this.color, globalAlpha: this.alpha }) } build() { NavDestination() { Column() { Navbar({ title: $r("app.string.path_page_title") }) Stack({ alignContent: Alignment.Bottom }) { Canvas(this.context) .width(CommonConstants.ONE_HUNDRED_PERCENT) .layoutWeight(1) .backgroundColor($r('sys.color.white')) .onReady(() => { // CanvasUtils 初始化 CanvasDrawUtils.init(this.context) }) .onTouch((event: TouchEvent) => { // 路径绘制, 传入event 对象进行绘制 CanvasDrawUtils.drawPath(event) }) } .width(CommonConstants.ONE_HUNDRED_PERCENT) .layoutWeight(1) // 省略代码... } } .hideTitleBar(true) } } ``` ## [鸿蒙相关工具仓库首页](https://gitee.com/Fie_Ryan) ``` https://gitee.com/Fie_Ryan ```