• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (c) 2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16import { common2D, drawing } from '@kit.ArkGraphics2D';
17import { DrawContext, FrameNode, NodeController, RenderNode, Size } from '@kit.ArkUI';
18import { image } from '@kit.ImageKit';
19
20/**
21 * MyRenderNode类,初始化画笔和绘制路径
22 */
23export class MyRenderNode extends RenderNode {
24  path: drawing.Path = new drawing.Path(); // 新建路径对象,用于绘制手指移动轨迹
25  pen: drawing.Pen = new drawing.Pen(); // 创建一个画笔Pen对象,Pen对象用于形状的边框线绘制
26  blendMode: drawing.BlendMode = drawing.BlendMode.SRC_OVER; // 画笔的颜色混合模式
27  lineStrokeWidth: number = 0; // 画笔线宽
28
29  constructor() {
30    super();
31    // 设置画笔颜色
32    const penColor: common2D.Color = {
33      alpha: 0xFF,
34      red: 0xFA,
35      green: 0x64,
36      blue: 0x00
37    };
38    this.pen.setColor(penColor);
39    // 设置画笔开启反走样,可以使得图形的边缘在显示时更平滑
40    this.pen.setAntiAlias(true);
41    // 开启画笔的抖动绘制效果。抖动绘制可以使得绘制出的颜色更加真实。
42    this.pen.setDither(true);
43    // 设置画笔绘制转角的样式为圆头
44    this.pen.setJoinStyle(drawing.JoinStyle.ROUND_JOIN);
45    // 设置画笔线帽的样式,即画笔在绘制线段时在线段头尾端点的样式为半圆弧
46    this.pen.setCapStyle(drawing.CapStyle.ROUND_CAP);
47  }
48
49  // RenderNode进行绘制时会调用draw方法
50  draw(context: DrawContext): void {
51    const canvas = context.canvas;
52    // 设置画笔的颜色混合模式,根据不同的混合模式实现涂鸦和擦除效果
53    this.pen.setBlendMode(this.blendMode);
54    // 设置画笔的线宽,单位px
55    this.pen.setStrokeWidth(this.lineStrokeWidth);
56    // 将Pen画笔设置到canvas中
57    canvas.attachPen(this.pen);
58    // 绘制path
59    canvas.drawPath(this.path);
60  }
61}
62
63/**
64 * MyImageRenderNode类,绘制和记录画布图案的pixelMap
65 */
66export class MyImageRenderNode extends RenderNode {
67  pixelMapHistory: image.PixelMap[] = []; // 记录每次绘制后画布的pixelMap
68  cacheStack: image.PixelMap[] = []; // 记录撤销时从pixelMapHistory中出栈的pixelMap,恢复时使用
69
70  // RenderNode进行绘制时会调用draw方法
71  draw(context: DrawContext): void {
72    const canvas = context.canvas;
73    if (this.pixelMapHistory.length !== 0) {
74      // 使用drawImage绘制pixelMapHistory栈顶的pixelMap
75      canvas.drawImage(this.pixelMapHistory[this.pixelMapHistory.length - 1], 0, 0);
76    }
77  }
78}
79
80/**
81 * NodeController的子类MyNodeController
82 */
83export class MyNodeController extends NodeController {
84  private rootNode: FrameNode | null = null; // 根节点
85  rootRenderNode: RenderNode | null = null; // 从NodeController根节点获取的RenderNode,用于添加和删除新创建的MyRenderNode实例
86
87  // MyNodeController实例绑定的NodeContainer创建时触发,创建根节点rootNode并将其挂载至NodeContainer
88  makeNode(uiContext: UIContext): FrameNode {
89    this.rootNode = new FrameNode(uiContext);
90    if (this.rootNode !== null) {
91      this.rootRenderNode = this.rootNode.getRenderNode();
92    }
93    return this.rootNode;
94  }
95
96  // 绑定的NodeContainer布局时触发,获取NodeContainer的宽高
97  aboutToResize(size: Size): void {
98    if (this.rootRenderNode !== null) {
99      // NodeContainer布局完成后设置rootRenderNode的背景透明
100      this.rootRenderNode.backgroundColor = 0X00000000;
101      // rootRenderNode的位置从组件NodeContainer的左上角(0,0)坐标开始,大小为NodeContainer的宽高
102      this.rootRenderNode.frame = {
103        x: 0,
104        y: 0,
105        width: size.width,
106        height: size.height
107      };
108    }
109  }
110
111  // 添加节点
112  addNode(node: RenderNode): void {
113    if (this.rootNode === null) {
114      return;
115    }
116    if (this.rootRenderNode !== null) {
117      this.rootRenderNode.appendChild(node);
118    }
119  }
120
121  // 清空节点
122  clearNodes(): void {
123    if (this.rootNode === null) {
124      return;
125    }
126    if (this.rootRenderNode !== null) {
127      this.rootRenderNode.clearChildren();
128    }
129  }
130}