Canvas绘制水印并动态修改覆盖区域的功能
======================

#### 问题现象

实现一个页面容器的水印效果，同时需要实现Canvas动态设置宽高，达到调整水印覆盖区域大小的效果。

#### 效果预览

![](https://contentcenter-vali-drcn.dbankcdn.cn/pvt_2/DeveloperAlliance_scene_100_1/40/v3/lbTAiqXyS_eHMXWvvWr6KA/zh-cn_image_0000002658963477.png?HW-CC-KV=V1&HW-CC-Date=20260709T134050Z&HW-CC-Expire=86400&HW-CC-Sign=28467E2B4A883F56F24495896B8B96E422C4987B92B8B104C97CA25CB3C87966 "点击放大")

修改宽高后：

![](https://contentcenter-vali-drcn.dbankcdn.cn/pvt_2/DeveloperAlliance_scene_100_1/b1/v3/siH5dPrxTsCt2nhig1VC9Q/zh-cn_image_0000002628604258.png?HW-CC-KV=V1&HW-CC-Date=20260709T134050Z&HW-CC-Expire=86400&HW-CC-Sign=7EA78806C3AC6FF3DD8358A895B9B701C10563D6C17E6B8E20A683976AB08A35 "点击放大")

#### 背景知识

*   [Canvas](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-components-canvas-canvas)提供画布组件，用于自定义绘制图形。
*   组件内部使用[@State装饰器](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/arkts-state#装饰器使用规则说明)声明相关的变量，能够在其值发生变化时自动触发与之直接绑定的UI组件进行刷新，从而实现界面的动态更新。

#### 解决方案

1.  创建Canvas画布，在画布上绘制水印。
2.  通过将声明的状态变量分别绑定至Canvas组件的width和height属性，实现Canvas宽高动态设置与响应式更新。

@Entry
@Component
export struct DrawWatermarkDemo {
  private settings: RenderingContextSettings \= new RenderingContextSettings(true);
  private context: CanvasRenderingContext2D \= new CanvasRenderingContext2D(this.settings);
  _// 画布宽高_
  @State markWidth: string \= '100%';
  @State markHeight: string \= '100%';
 _ // 水印间距_
  watermarkWidth: number \= 100;
  watermarkHeight: number \= 100;
 _ // 水印标识_
  watermarkText: string \= '默认水印';
 _ // 旋转角度_
  rotationAngle: number \= -30;
 _ // 水印颜色_
  @State fillColor: string | number | CanvasGradient | CanvasPattern \= '#10000000';
 _ // 水印字体大小_
  font: string \= '16vp';

  draw() {
    this.context.fillStyle \= this.fillColor;
    this.context.font \= this.font;
    const colCount \= Math.ceil(this.context.width / this.watermarkWidth);
    const rowCount \= Math.ceil(this.context.height / this.watermarkHeight);
    for (let col \= 0; col <\= colCount; col++) {
      let row \= 0;
      for (; row <\= rowCount; row++) {
        const angle \= this.rotationAngle \* Math.PI / 180;
        this.context.rotate(angle);
        const positionX \= this.rotationAngle \> 0 ? this.watermarkHeight \* Math.tan(angle) : 0;
        const positionY \= this.rotationAngle \> 0 ? 0 : this.watermarkWidth \* Math.tan(\-angle);
        this.context.fillText(this.watermarkText, positionX, positionY);
        this.context.rotate(\-angle);
        this.context.translate(0, this.watermarkHeight);
      }
      this.context.translate(0, -this.watermarkHeight \* row);
      this.context.translate(this.watermarkWidth, 0);
    }
  };

  build() {
    Stack({ alignContent: Alignment.Top }) {
      Column() {
        Text('width:').margin({ top: 30, bottom: 16 });
        TextInput({
          text: $$this.markWidth
        }).margin({ left: 16, right: 16 });
        Text('height:').margin({ top: 24, bottom: 16 });
        TextInput({
          text: $$this.markHeight
        }).margin({ left: 16, right: 16 });
      };

      Canvas(this.context)
        .width(this.markWidth) _// 动态赋予宽度_
        .height(this.markHeight) _// 动态赋予高度_
        .backgroundColor('#12bab8b8')
        .hitTestBehavior(HitTestMode.Transparent)
        .expandSafeArea(\[SafeAreaType.SYSTEM\], \[SafeAreaEdge.TOP, SafeAreaEdge.BOTTOM\])
        .onReady(() \=\> {
          this.draw();
        });
    }
    .width('100%')
    .height('100%');
  };
};

#### 常见FAQ

Q：如何实现移动水印位置的效果？

A：通过[position属性](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-universal-attributes-location#position)动态设置Canvas组件位置即可。