diff --git a/example/app.json b/example/app.json index 9e3fa40163..c82479ef45 100644 --- a/example/app.json +++ b/example/app.json @@ -90,7 +90,8 @@ "pages/col/col", "pages/col/skyline/col", "pages/color-picker/color-picker", - "pages/guide/guide" + "pages/guide/guide", + "pages/watermark/watermark" ], "subpackages": [ { diff --git a/example/pages/home/data/display.ts b/example/pages/home/data/display.ts index 42e91a8a20..6681536da1 100644 --- a/example/pages/home/data/display.ts +++ b/example/pages/home/data/display.ts @@ -79,6 +79,10 @@ const display = { name: 'Tag', label: '标签', }, + { + name: 'Watermark', + label: '水印', + }, ], }; diff --git a/example/project.config.json b/example/project.config.json index 2cc0040508..acdbd2c807 100644 --- a/example/project.config.json +++ b/example/project.config.json @@ -406,6 +406,12 @@ "query": "", "scene": null }, + { + "name": "watermark", + "pathName": "pages/watermark/watermark", + "query": "", + "scene": null + }, { "id": -1, "name": "search", diff --git a/packages/components/watermark/README.en-US.md b/packages/components/watermark/README.en-US.md new file mode 100644 index 0000000000..c2915aeaa0 --- /dev/null +++ b/packages/components/watermark/README.en-US.md @@ -0,0 +1,42 @@ +:: BASE_DOC :: + +## API + +### Watermark Props + +name | type | default | description | required +-- | -- | -- | -- | -- +style | Object | - | CSS(Cascading Style Sheets) | N +custom-style | Object | - | CSS(Cascading Style Sheets),used to set style on virtual component | N +alpha | Number | 1 | \- | N +content | String / Slot | - | [see more ts definition](https://github.com/Tencent/tdesign-miniprogram/blob/develop/src/common/common.ts) | N +height | Number | - | \- | N +is-repeat | Boolean | true | \- | N +line-space | Number | 16 | \- | N +movable | Boolean | false | \- | N +move-interval | Number | 3000 | \- | N +offset | Array | - | Typescript:`Array` | N +removable | Boolean | true | \- | N +rotate | Number | -22 | \- | N +watermark-content | Object / Array | - | Typescript:`WatermarkText\|WatermarkImage\|Array` | N +width | Number | - | \- | N +x | Number | - | \- | N +y | Number | - | \- | N +z-index | Number | - | \- | N + +### WatermarkText + +name | type | default | description | required +-- | -- | -- | -- | -- +font-color | String | rgba(0,0,0,0.1) | \- | N +font-family | String | - | font-family configuration for watermark text | N +font-size | Number | 16 | \- | N +font-weight | String | normal | options: normal/lighter/bold/bolder | N +text | String | - | \- | N + +### WatermarkImage + +name | type | default | description | required +-- | -- | -- | -- | -- +is-grayscale | Boolean | false | \- | N +url | String | - | \- | N diff --git a/packages/components/watermark/README.md b/packages/components/watermark/README.md new file mode 100644 index 0000000000..70ec729e28 --- /dev/null +++ b/packages/components/watermark/README.md @@ -0,0 +1,42 @@ +:: BASE_DOC :: + +## API + +### Watermark Props + +名称 | 类型 | 默认值 | 描述 | 必传 +-- | -- | -- | -- | -- +style | Object | - | 样式 | N +custom-style | Object | - | 样式,一般用于开启虚拟化组件节点场景 | N +alpha | Number | 1 | 水印整体透明度,取值范围 [0-1] | N +content | String / Slot | - | 水印所覆盖的内容节点。[通用类型定义](https://github.com/Tencent/tdesign-miniprogram/blob/develop/src/common/common.ts) | N +height | Number | - | 水印高度 | N +is-repeat | Boolean | true | 水印是否重复出现 | N +line-space | Number | 16 | 行间距,只作用在多行(`content` 配置为数组)情况下 | N +movable | Boolean | false | 水印是否可移动 | N +move-interval | Number | 3000 | 水印发生运动位移的间隙,单位:毫秒 | N +offset | Array | - | 水印在画布上绘制的水平和垂直偏移量,正常情况下水印绘制在中间位置,即 `offset = [gapX / 2, gapY / 2]`。TS 类型:`Array` | N +removable | Boolean | true | 水印是否可被删除 | N +rotate | Number | -22 | 水印旋转的角度,单位 ° | N +watermark-content | Object / Array | - | 水印内容,需要显示多行情况下可配置为数组。TS 类型:`WatermarkText\|WatermarkImage\|Array` | N +width | Number | - | 水印宽度 | N +x | Number | - | 水印之间的水平间距 | N +y | Number | - | 水印之间的垂直间距 | N +z-index | Number | - | 水印元素的 `z-index`,默认值写在 CSS 中 | N + +### WatermarkText + +名称 | 类型 | 默认值 | 描述 | 必传 +-- | -- | -- | -- | -- +font-color | String | rgba(0,0,0,0.1) | 水印文本文字颜色 | N +font-family | String | - | 水印文本文字字体 | N +font-size | Number | 16 | 水印文本文字大小 | N +font-weight | String | normal | 水印文本文字粗细。可选项:normal/lighter/bold/bolder | N +text | String | - | 水印文本内容 | N + +### WatermarkImage + +名称 | 类型 | 默认值 | 描述 | 必传 +-- | -- | -- | -- | -- +is-grayscale | Boolean | false | 水印图片是否需要灰阶显示 | N +url | String | - | 水印图片源地址,为了显示清楚,建议导出 2 倍或 3 倍图 | N diff --git a/packages/components/watermark/_example/base/index.js b/packages/components/watermark/_example/base/index.js new file mode 100644 index 0000000000..b3f9d70c1e --- /dev/null +++ b/packages/components/watermark/_example/base/index.js @@ -0,0 +1,5 @@ +Component({ + data: { + watermark: { text: '文字水印' }, + }, +}); diff --git a/packages/components/watermark/_example/base/index.json b/packages/components/watermark/_example/base/index.json new file mode 100644 index 0000000000..66c4599b55 --- /dev/null +++ b/packages/components/watermark/_example/base/index.json @@ -0,0 +1,6 @@ +{ + "component": true, + "usingComponents": { + "t-watermark": "tdesign-miniprogram/watermark/watermark" + } +} diff --git a/packages/components/watermark/_example/base/index.wxml b/packages/components/watermark/_example/base/index.wxml new file mode 100644 index 0000000000..d06fafb820 --- /dev/null +++ b/packages/components/watermark/_example/base/index.wxml @@ -0,0 +1,3 @@ + + + diff --git a/packages/components/watermark/_example/base/index.wxss b/packages/components/watermark/_example/base/index.wxss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/packages/components/watermark/_example/gray/index.js b/packages/components/watermark/_example/gray/index.js new file mode 100644 index 0000000000..c56a42e136 --- /dev/null +++ b/packages/components/watermark/_example/gray/index.js @@ -0,0 +1,8 @@ +Component({ + data: { + watermark: { + url: 'https://tdesign.gtimg.com/starter/brand-logo-light.png', + isGrayscale: true, + }, + }, +}); diff --git a/packages/components/watermark/_example/gray/index.json b/packages/components/watermark/_example/gray/index.json new file mode 100644 index 0000000000..66c4599b55 --- /dev/null +++ b/packages/components/watermark/_example/gray/index.json @@ -0,0 +1,6 @@ +{ + "component": true, + "usingComponents": { + "t-watermark": "tdesign-miniprogram/watermark/watermark" + } +} diff --git a/packages/components/watermark/_example/gray/index.wxml b/packages/components/watermark/_example/gray/index.wxml new file mode 100644 index 0000000000..e1b5c07418 --- /dev/null +++ b/packages/components/watermark/_example/gray/index.wxml @@ -0,0 +1,3 @@ + + + diff --git a/packages/components/watermark/_example/gray/index.wxss b/packages/components/watermark/_example/gray/index.wxss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/packages/components/watermark/_example/image/index.js b/packages/components/watermark/_example/image/index.js new file mode 100644 index 0000000000..b766d73688 --- /dev/null +++ b/packages/components/watermark/_example/image/index.js @@ -0,0 +1,5 @@ +Component({ + data: { + watermark: { url: 'https://tdesign.gtimg.com/starter/brand-logo-light.png' }, + }, +}); diff --git a/packages/components/watermark/_example/image/index.json b/packages/components/watermark/_example/image/index.json new file mode 100644 index 0000000000..66c4599b55 --- /dev/null +++ b/packages/components/watermark/_example/image/index.json @@ -0,0 +1,6 @@ +{ + "component": true, + "usingComponents": { + "t-watermark": "tdesign-miniprogram/watermark/watermark" + } +} diff --git a/packages/components/watermark/_example/image/index.wxml b/packages/components/watermark/_example/image/index.wxml new file mode 100644 index 0000000000..cda89ad33a --- /dev/null +++ b/packages/components/watermark/_example/image/index.wxml @@ -0,0 +1,3 @@ + + + diff --git a/packages/components/watermark/_example/image/index.wxss b/packages/components/watermark/_example/image/index.wxss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/packages/components/watermark/_example/move-image/index.js b/packages/components/watermark/_example/move-image/index.js new file mode 100644 index 0000000000..0d5ec5374a --- /dev/null +++ b/packages/components/watermark/_example/move-image/index.js @@ -0,0 +1,5 @@ +Component({ + data: { + watermark: { url: 'https://tdesign.gtimg.com/site/baseLogo-light.png' }, + }, +}); diff --git a/packages/components/watermark/_example/move-image/index.json b/packages/components/watermark/_example/move-image/index.json new file mode 100644 index 0000000000..66c4599b55 --- /dev/null +++ b/packages/components/watermark/_example/move-image/index.json @@ -0,0 +1,6 @@ +{ + "component": true, + "usingComponents": { + "t-watermark": "tdesign-miniprogram/watermark/watermark" + } +} diff --git a/packages/components/watermark/_example/move-image/index.wxml b/packages/components/watermark/_example/move-image/index.wxml new file mode 100644 index 0000000000..c66bb19f6c --- /dev/null +++ b/packages/components/watermark/_example/move-image/index.wxml @@ -0,0 +1,3 @@ + + + diff --git a/packages/components/watermark/_example/move-image/index.wxss b/packages/components/watermark/_example/move-image/index.wxss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/packages/components/watermark/_example/move-text/index.js b/packages/components/watermark/_example/move-text/index.js new file mode 100644 index 0000000000..b3f9d70c1e --- /dev/null +++ b/packages/components/watermark/_example/move-text/index.js @@ -0,0 +1,5 @@ +Component({ + data: { + watermark: { text: '文字水印' }, + }, +}); diff --git a/packages/components/watermark/_example/move-text/index.json b/packages/components/watermark/_example/move-text/index.json new file mode 100644 index 0000000000..66c4599b55 --- /dev/null +++ b/packages/components/watermark/_example/move-text/index.json @@ -0,0 +1,6 @@ +{ + "component": true, + "usingComponents": { + "t-watermark": "tdesign-miniprogram/watermark/watermark" + } +} diff --git a/packages/components/watermark/_example/move-text/index.wxml b/packages/components/watermark/_example/move-text/index.wxml new file mode 100644 index 0000000000..9e3d2948a4 --- /dev/null +++ b/packages/components/watermark/_example/move-text/index.wxml @@ -0,0 +1,3 @@ + + + diff --git a/packages/components/watermark/_example/move-text/index.wxss b/packages/components/watermark/_example/move-text/index.wxss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/packages/components/watermark/_example/multi-line-gray/index.js b/packages/components/watermark/_example/multi-line-gray/index.js new file mode 100644 index 0000000000..49fdd6ed1f --- /dev/null +++ b/packages/components/watermark/_example/multi-line-gray/index.js @@ -0,0 +1,8 @@ +Component({ + data: { + watermark: [ + { text: '水印文本', fontColor: 'black' }, + { url: 'https://tdesign.gtimg.com/starter/brand-logo-light.png', isGrayscale: true }, + ], + }, +}); diff --git a/packages/components/watermark/_example/multi-line-gray/index.json b/packages/components/watermark/_example/multi-line-gray/index.json new file mode 100644 index 0000000000..66c4599b55 --- /dev/null +++ b/packages/components/watermark/_example/multi-line-gray/index.json @@ -0,0 +1,6 @@ +{ + "component": true, + "usingComponents": { + "t-watermark": "tdesign-miniprogram/watermark/watermark" + } +} diff --git a/packages/components/watermark/_example/multi-line-gray/index.wxml b/packages/components/watermark/_example/multi-line-gray/index.wxml new file mode 100644 index 0000000000..ba335eb059 --- /dev/null +++ b/packages/components/watermark/_example/multi-line-gray/index.wxml @@ -0,0 +1,11 @@ + + + diff --git a/packages/components/watermark/_example/multi-line-gray/index.wxss b/packages/components/watermark/_example/multi-line-gray/index.wxss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/packages/components/watermark/_example/multi-line/index.js b/packages/components/watermark/_example/multi-line/index.js new file mode 100644 index 0000000000..5dcafe7b5d --- /dev/null +++ b/packages/components/watermark/_example/multi-line/index.js @@ -0,0 +1,8 @@ +Component({ + data: { + watermark: [ + { text: '水印文本', fontColor: 'black' }, + { url: 'https://tdesign.gtimg.com/starter/brand-logo-light.png' }, + ], + }, +}); diff --git a/packages/components/watermark/_example/multi-line/index.json b/packages/components/watermark/_example/multi-line/index.json new file mode 100644 index 0000000000..66c4599b55 --- /dev/null +++ b/packages/components/watermark/_example/multi-line/index.json @@ -0,0 +1,6 @@ +{ + "component": true, + "usingComponents": { + "t-watermark": "tdesign-miniprogram/watermark/watermark" + } +} diff --git a/packages/components/watermark/_example/multi-line/index.wxml b/packages/components/watermark/_example/multi-line/index.wxml new file mode 100644 index 0000000000..ba335eb059 --- /dev/null +++ b/packages/components/watermark/_example/multi-line/index.wxml @@ -0,0 +1,11 @@ + + + diff --git a/packages/components/watermark/_example/multi-line/index.wxss b/packages/components/watermark/_example/multi-line/index.wxss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/packages/components/watermark/_example/watermark.js b/packages/components/watermark/_example/watermark.js new file mode 100644 index 0000000000..560d44d430 --- /dev/null +++ b/packages/components/watermark/_example/watermark.js @@ -0,0 +1 @@ +Page({}); diff --git a/packages/components/watermark/_example/watermark.json b/packages/components/watermark/_example/watermark.json new file mode 100644 index 0000000000..4424cd9deb --- /dev/null +++ b/packages/components/watermark/_example/watermark.json @@ -0,0 +1,12 @@ +{ + "navigationBarTitleText": "Watermark", + "usingComponents": { + "base": "./base", + "image-watermark": "./image", + "multi-line-watermark": "./multi-line", + "multi-line-gray-watermark": "./multi-line-gray", + "move-text-watermark": "./move-text", + "move-image-watermark": "./move-image", + "gray-watermark": "./gray" + } +} diff --git a/packages/components/watermark/_example/watermark.wxml b/packages/components/watermark/_example/watermark.wxml new file mode 100644 index 0000000000..4c4264418c --- /dev/null +++ b/packages/components/watermark/_example/watermark.wxml @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/components/watermark/_example/watermark.wxss b/packages/components/watermark/_example/watermark.wxss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/packages/components/watermark/props.ts b/packages/components/watermark/props.ts new file mode 100644 index 0000000000..c6df0f41e0 --- /dev/null +++ b/packages/components/watermark/props.ts @@ -0,0 +1,78 @@ +/* eslint-disable */ + +/** + * 该文件为脚本自动生成文件,请勿随意修改。如需修改请联系 PMC + * */ + +import { TdWatermarkProps } from './type'; +const props: TdWatermarkProps = { + /** 水印整体透明度,取值范围 [0-1] */ + alpha: { + type: Number, + value: 1, + }, + /** 水印所覆盖的内容节点 */ + content: { + type: String, + }, + /** 水印高度 */ + height: { + type: Number, + }, + /** 水印是否重复出现 */ + isRepeat: { + type: Boolean, + value: true, + }, + /** 行间距,只作用在多行(`content` 配置为数组)情况下 */ + lineSpace: { + type: Number, + value: 16, + }, + /** 水印是否可移动 */ + movable: { + type: Boolean, + value: false, + }, + /** 水印发生运动位移的间隙,单位:毫秒 */ + moveInterval: { + type: Number, + value: 3000, + }, + /** 水印在画布上绘制的水平和垂直偏移量,正常情况下水印绘制在中间位置,即 `offset = [gapX / 2, gapY / 2]` */ + offset: { + type: Array, + }, + /** 水印是否可被删除 */ + removable: { + type: Boolean, + value: true, + }, + /** 水印旋转的角度,单位 ° */ + rotate: { + type: Number, + value: -22, + }, + /** 水印内容,需要显示多行情况下可配置为数组 */ + watermarkContent: { + type: null, + }, + /** 水印宽度 */ + width: { + type: Number, + }, + /** 水印之间的水平间距 */ + x: { + type: Number, + }, + /** 水印之间的垂直间距 */ + y: { + type: Number, + }, + /** 水印元素的 `z-index`,默认值写在 CSS 中 */ + zIndex: { + type: Number, + }, +}; + +export default props; diff --git a/packages/components/watermark/type.ts b/packages/components/watermark/type.ts new file mode 100644 index 0000000000..54f677a7a4 --- /dev/null +++ b/packages/components/watermark/type.ts @@ -0,0 +1,161 @@ +/* eslint-disable */ + +/** + * 该文件为脚本自动生成文件,请勿随意修改。如需修改请联系 PMC + * */ + +export interface TdWatermarkProps { + /** + * 水印整体透明度,取值范围 [0-1] + * @default 1 + */ + alpha?: { + type: NumberConstructor; + value?: number; + }; + /** + * 水印所覆盖的内容节点 + */ + content?: { + type: StringConstructor; + value?: string; + }; + /** + * 水印高度 + */ + height?: { + type: NumberConstructor; + value?: number; + }; + /** + * 水印是否重复出现 + * @default true + */ + isRepeat?: { + type: BooleanConstructor; + value?: boolean; + }; + /** + * 行间距,只作用在多行(`content` 配置为数组)情况下 + * @default 16 + */ + lineSpace?: { + type: NumberConstructor; + value?: number; + }; + /** + * 水印是否可移动 + * @default false + */ + movable?: { + type: BooleanConstructor; + value?: boolean; + }; + /** + * 水印发生运动位移的间隙,单位:毫秒 + * @default 3000 + */ + moveInterval?: { + type: NumberConstructor; + value?: number; + }; + /** + * 水印在画布上绘制的水平和垂直偏移量,正常情况下水印绘制在中间位置,即 `offset = [gapX / 2, gapY / 2]` + */ + offset?: { + type: ArrayConstructor; + value?: Array; + }; + /** + * 水印是否可被删除 + * @default true + */ + removable?: { + type: BooleanConstructor; + value?: boolean; + }; + /** + * 水印旋转的角度,单位 ° + * @default -22 + */ + rotate?: { + type: NumberConstructor; + value?: number; + }; + /** + * 水印内容,需要显示多行情况下可配置为数组 + */ + watermarkContent?: { + type: null; + value?: WatermarkText | WatermarkImage | Array; + }; + /** + * 水印宽度 + */ + width?: { + type: NumberConstructor; + value?: number; + }; + /** + * 水印之间的水平间距 + */ + x?: { + type: NumberConstructor; + value?: number; + }; + /** + * 水印之间的垂直间距 + */ + y?: { + type: NumberConstructor; + value?: number; + }; + /** + * 水印元素的 `z-index`,默认值写在 CSS 中 + */ + zIndex?: { + type: NumberConstructor; + value?: number; + }; +} + +export interface WatermarkText { + /** + * 水印文本文字颜色 + * @default rgba(0,0,0,0.1) + */ + fontColor?: string; + /** + * 水印文本文字字体 + * @default '' + */ + fontFamily?: string; + /** + * 水印文本文字大小 + * @default 16 + */ + fontSize?: number; + /** + * 水印文本文字粗细 + * @default normal + */ + fontWeight?: 'normal' | 'lighter' | 'bold' | 'bolder'; + /** + * 水印文本内容 + * @default '' + */ + text?: string; +} + +export interface WatermarkImage { + /** + * 水印图片是否需要灰阶显示 + * @default false + */ + isGrayscale?: boolean; + /** + * 水印图片源地址,为了显示清楚,建议导出 2 倍或 3 倍图 + * @default '' + */ + url?: string; +} diff --git a/packages/components/watermark/utils/generateBase64Url.ts b/packages/components/watermark/utils/generateBase64Url.ts new file mode 100644 index 0000000000..68c4487c5a --- /dev/null +++ b/packages/components/watermark/utils/generateBase64Url.ts @@ -0,0 +1,69 @@ +import { systemInfo } from '../../common/utils'; + +export default function generateBase64Url( + canvas, + { width, height, gapX, gapY, offsetLeft, offsetTop, rotate, alpha, watermarkContent, lineSpace, watermarkColor }, + onFinish, +) { + const ctx = canvas.getContext('2d'); + if (!ctx) { + console.warn('当前环境不支持Canvas, 无法绘制水印'); + onFinish(''); + return; + } + const ratio = systemInfo.pixelRatio || 1; + const canvasWidth = (gapX + width) * ratio; + const canvasHeight = (gapY + height) * ratio; + + canvas.width = canvasWidth; + canvas.height = canvasHeight; + + ctx.translate(offsetLeft * ratio, offsetTop * ratio); + ctx.rotate((Math.PI / 180) * Number(rotate)); + ctx.globalAlpha = alpha; + + const markWidth = width * ratio; + const markHeight = height * ratio; + + ctx.fillStyle = 'transparent'; + ctx.fillRect(0, 0, markWidth, markHeight); + + const contents = Array.isArray(watermarkContent) ? watermarkContent : [{ ...watermarkContent }]; + + let top = 0; + contents.forEach((item) => { + if (item.url) { + const { url, isGrayscale = false } = item; + item.top = top; + top += height; + const image = canvas.createImage(); + image.src = url; + image.onload = () => { + ctx.drawImage(image, 0, item.top * ratio, width * ratio, height * ratio); + if (isGrayscale) { + const imgData = ctx.getImageData(0, 0, ctx.canvas.width, ctx.canvas.height); + const pixels = imgData.data; + for (let i = 0; i < pixels.length; i += 4) { + const lightness = (pixels[i] + pixels[i + 1] + pixels[i + 2]) / 3; + pixels[i] = lightness; + pixels[i + 1] = lightness; + pixels[i + 2] = lightness; + } + ctx.putImageData(imgData, 0, 0); + } + onFinish(canvas.toDataURL()); + }; + } else if (item.text) { + const { text, fontColor = watermarkColor, fontSize = 16, fontFamily = undefined, fontWeight = 'normal' } = item; + item.top = top; + top += lineSpace; + const markSize = Number(fontSize) * ratio; + ctx.font = `normal normal ${fontWeight} ${markSize}px/${markHeight}px ${fontFamily}`; + ctx.textAlign = 'start'; + ctx.textBaseline = 'top'; + ctx.fillStyle = fontColor; + ctx.fillText(text, 0, item.top * ratio); + } + }); + onFinish(canvas.toDataURL()); +} diff --git a/packages/components/watermark/utils/randomMovingStyle.ts b/packages/components/watermark/utils/randomMovingStyle.ts new file mode 100644 index 0000000000..2a8a51c170 --- /dev/null +++ b/packages/components/watermark/utils/randomMovingStyle.ts @@ -0,0 +1,27 @@ +/* eslint-disable no-nested-ternary */ +export default function randomMovingStyle() { + const align = Math.floor(Math.random() * 4); + const p1 = Math.floor(Math.random() * 70) + 30; + const leftTopLimit = 0; + const bottomLimit = 95; + const rightLimit = 90; + const left0 = align === 1 ? rightLimit : align === 3 ? leftTopLimit : p1; + const left25 = align === 0 ? rightLimit : align === 2 ? leftTopLimit : 100 - p1; + const left50 = align === 1 ? leftTopLimit : align === 3 ? rightLimit : 100 - p1; + const left75 = align === 0 ? leftTopLimit : align === 2 ? rightLimit : p1; + const top0 = align === 0 ? leftTopLimit : align === 2 ? bottomLimit : p1; + const top25 = align === 1 ? bottomLimit : align === 3 ? leftTopLimit : p1; + const top50 = align === 0 ? bottomLimit : align === 2 ? leftTopLimit : 100 - p1; + const top75 = align === 1 ? leftTopLimit : align === 3 ? bottomLimit : 100 - p1; + + return { + left0: `${left0}%`, + left25: `${left25}%`, + left50: `${left50}%`, + left75: `${left75}%`, + top0: `${top0}%`, + top25: `${top25}%`, + top50: `${top50}%`, + top75: `${top75}%`, + }; +} diff --git a/packages/components/watermark/watermark.json b/packages/components/watermark/watermark.json new file mode 100644 index 0000000000..4f0a3f08c7 --- /dev/null +++ b/packages/components/watermark/watermark.json @@ -0,0 +1,5 @@ +{ + "component": true, + "styleIsolation": "apply-shared", + "usingComponents": {} +} diff --git a/packages/components/watermark/watermark.less b/packages/components/watermark/watermark.less new file mode 100644 index 0000000000..9d3ad7753b --- /dev/null +++ b/packages/components/watermark/watermark.less @@ -0,0 +1,31 @@ +@import '../common/style/base.less'; + +.@{prefix}-watermark { + position: relative; + overflow: hidden; + width: 100%; +} + +@keyframes watermark { + 0% { + left: var(--watermark-left-0); + top: var(--watermark-top-0); + } + 25% { + left: var(--watermark-left-25); + top: var(--watermark-top-25); + } + 50% { + left: var(--watermark-left-50); + top: var(--watermark-top-50); + transform: translateX(-100%); + } + 75% { + left: var(--watermark-left-75); + top: var(--watermark-top-75); + } + 100% { + left: var(--watermark-left-0); + top: var(--watermark-top-0); + } +} diff --git a/packages/components/watermark/watermark.ts b/packages/components/watermark/watermark.ts new file mode 100644 index 0000000000..ddb2ab7efb --- /dev/null +++ b/packages/components/watermark/watermark.ts @@ -0,0 +1,108 @@ +import { SuperComponent, wxComponent } from '../common/src/index'; +import config from '../common/config'; +import props from './props'; +import generateBase64Url from './utils/generateBase64Url'; +import randomMovingStyle from './utils/randomMovingStyle'; +import { appBaseInfo } from '../common/utils'; + +const { prefix } = config; +const name = `${prefix}-watermark`; + +@wxComponent() +export default class Watermark extends SuperComponent { + externalClasses = [`${prefix}-class`]; + + properties = props; + + data = { + classPrefix: name, + watermarkStyle: {}, + }; + + lifetimes = { + attached() { + this.renderWatermark(); + }, + }; + + observers = { + 'watermarkContent, movable, rotate, x, y, width, height, alpha, lineSpace, moveInterval, zIndex, rotate, offset, removable, isRepeat'() { + this.renderWatermark(); + }, + }; + + methods = { + watermarkColor() { + return appBaseInfo.theme === 'dark' ? 'rgba(238, 238, 238, 0.1)' : 'rgba(0, 0, 0, 0.1)'; + }, + + renderWatermark() { + const query = wx.createSelectorQuery().in(this); + query + .select('#watermarkCanvas') + .fields({ node: true, size: true }) + .exec(async (res) => { + if (!res[0]?.node) { + console.error('Canvas node not found'); + return; + } + const canvas = res[0].node; + const props = this.properties; + const gapX = props.movable ? 0 : props.x; + const gapY = props.movable ? 0 : props.y; + const offset = props.offset || []; + const offsetLeft = offset[0] || gapX / 2; + const offsetTop = offset[1] || gapY / 2; + + const bgImageOptions = { + width: props.width, + height: props.height, + rotate: props.movable ? 0 : props.rotate, + lineSpace: props.lineSpace, + alpha: props.alpha, + gapX: gapX, + gapY: gapY, + watermarkContent: props.watermarkContent, + offsetLeft: offsetLeft, + offsetTop: offsetTop, + watermarkColor: this.watermarkColor(), + }; + generateBase64Url(canvas, bgImageOptions, (base64Url) => { + let animationVars = {}; + if (props.movable) { + const { left0, left25, left50, left75, top0, top25, top50, top75 } = randomMovingStyle(); + animationVars = { + '--watermark-left-0': left0, + '--watermark-left-25': left25, + '--watermark-left-50': left50, + '--watermark-left-75': left75, + '--watermark-top-0': top0, + '--watermark-top-25': top25, + '--watermark-top-50': top50, + '--watermark-top-75': top75, + }; + } + + this.setData({ + watermarkStyle: { + zIndex: props.zIndex, + position: 'absolute', + left: 0, + right: 0, + top: 0, + bottom: 0, + width: '100%', + height: '100%', + backgroundSize: `${gapX + props.width}px`, + pointerEvents: 'none', + backgroundRepeat: props.movable ? 'no-repeat' : 'repeat', + backgroundImage: `url('${base64Url}')`, + animation: props.movable ? `watermark infinite ${(props.moveInterval * 4) / 60}s` : 'none', + ...animationVars, + }, + }); + }); + }); + }, + }; +} diff --git a/packages/components/watermark/watermark.wxml b/packages/components/watermark/watermark.wxml new file mode 100644 index 0000000000..59781b525b --- /dev/null +++ b/packages/components/watermark/watermark.wxml @@ -0,0 +1,9 @@ + + + + {{content}} + + + diff --git a/packages/tdesign-miniprogram-site/site.config.mjs b/packages/tdesign-miniprogram-site/site.config.mjs index bfedfca446..65d1bcd30a 100644 --- a/packages/tdesign-miniprogram-site/site.config.mjs +++ b/packages/tdesign-miniprogram-site/site.config.mjs @@ -482,6 +482,14 @@ export const docs = [ path: '/miniprogram/components/tag', component: () => import('@/tag/README.md'), }, + { + title: 'Watermark 水印', + titleEn: 'Watermark', + name: 'watermark', + meta: { docType: 'data' }, + path: '/miniprogram/components/watermark', + component: () => import('@/watermark/README.md'), + }, ], }, {